Implement blockchain logic
This commit is contained in:
@@ -2,6 +2,7 @@ from dataclasses import dataclass
|
||||
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey, Ed25519PublicKey
|
||||
from cryptography.exceptions import InvalidSignature
|
||||
import hashlib
|
||||
from multiprocessing import Lock
|
||||
import time
|
||||
|
||||
@dataclass
|
||||
@@ -13,6 +14,16 @@ class Transaction:
|
||||
transaction_fee: int
|
||||
signature: bytes
|
||||
|
||||
def from_bytes(transaction_raw):
|
||||
assert len(transaction_raw) == 148
|
||||
return Transaction(
|
||||
id: int.from_bytes(transaction_raw[0:4], "big"),
|
||||
sender: transaction_raw[4:36],
|
||||
receiver: transaction_raw[36:68],
|
||||
amount: int.from_bytes(transaction_raw[68:76], "big"),
|
||||
transaction_fee: int.from_bytes(transaction_raw[76:84], "big"),
|
||||
signature: transaction_raw[84:148],
|
||||
)
|
||||
def is_valid(self):
|
||||
sender_pubkey = Ed25519PublicKey.from_public_bytes(self.sender)
|
||||
msg = self.id.to_bytes(4, "big") + \
|
||||
@@ -49,11 +60,32 @@ class Block:
|
||||
difficulty_sum: int
|
||||
miner_pubkey: bytes
|
||||
transaction: Transaction
|
||||
own_hash: bytes
|
||||
balances: dict
|
||||
# (sender_pubkey, id) tuples
|
||||
used_transaction_ids: set
|
||||
valid: bool
|
||||
|
||||
def from_bytes(self, block_raw):
|
||||
assert len(block_raw) == 292
|
||||
transaction_raw = block_raw[144:292]
|
||||
if transaction_raw == 148 * b"\0":
|
||||
transaction = None
|
||||
else:
|
||||
transaction = Transaction.from_bytes(transaction_raw)
|
||||
block = Block(
|
||||
nonce: int.from_bytes(block_raw[0:8], "big"),
|
||||
timestamp: int.from_bytes(block_raw[8:16], "big"),
|
||||
previous_hash: block_raw[16:48],
|
||||
message: block_raw[48:80],
|
||||
difficulty_sum: int.from_bytes(block_raw[80:112], "big"),
|
||||
miner_pubkey: block_raw[112:144],
|
||||
transaction: transaction,
|
||||
own_hash: hashlib.sha256(block_raw).digest(),
|
||||
balances: None,
|
||||
used_transaction_ids: None,
|
||||
valid: False,
|
||||
)
|
||||
def validate(self, blockchain):
|
||||
if self.transaction is not None:
|
||||
if not self.transaction.is_valid():
|
||||
@@ -83,9 +115,7 @@ class Block:
|
||||
block_difficulty = max(calculated_difficulty, 2**28)
|
||||
if B_1_difficulty_sum + block_difficulty != self.difficulty_sum:
|
||||
return False
|
||||
block_raw = self.get_block_raw()
|
||||
block_hash = hashlib.sha256(block_raw).digest()
|
||||
self.valid = int.from_bytes(block_hash, "big") * block_difficulty < 2**256
|
||||
self.valid = int.from_bytes(self.own_hash, "big") * block_difficulty < 2**256
|
||||
if self.valid:
|
||||
self.calculate_balances(prev_block)
|
||||
self.calculate_used_transaction_ids(prev_block)
|
||||
@@ -141,5 +171,24 @@ class Blockchain:
|
||||
def __init__(self):
|
||||
# maps block hashes to block instances
|
||||
self.__block_map = {}
|
||||
self.__latest_block_hash = None
|
||||
self.__lock = Lock()
|
||||
def set_latest_block(self, block_hash):
|
||||
with self.__lock:
|
||||
new_block = self.get_block(block_hash)
|
||||
assert new_block is not None
|
||||
assert new_block.valid
|
||||
if self.__latest_block_hash is not None:
|
||||
current_difficulty_sum = self.__latest_block_hash.get_difficulty_info(1, self)
|
||||
new_difficulty_sum = new_block.get_difficulty_info(1, self)
|
||||
if new_difficulty_sum <= current_difficulty_sum:
|
||||
return
|
||||
self.__latest_block_hash = block_hash
|
||||
def add_block(self, block_raw):
|
||||
with self.__lock:
|
||||
block = Block.from_bytes(block_raw)
|
||||
self.__block_map[block.own_hash] = block
|
||||
return block
|
||||
def get_block(self, hash):
|
||||
return self.__block_map.get(hash)
|
||||
with self.__lock:
|
||||
return self.__block_map.get(hash)
|
||||
|
||||
Reference in New Issue
Block a user