diff --git a/blockchain.py b/blockchain.py index 04fc6e1..e13c0fc 100644 --- a/blockchain.py +++ b/blockchain.py @@ -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)