Implement blockchain logic

This commit is contained in:
2024-03-16 17:10:03 +01:00
parent 9204f87c56
commit 44598fc030

View File

@@ -2,6 +2,7 @@ from dataclasses import dataclass
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey, Ed25519PublicKey from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey, Ed25519PublicKey
from cryptography.exceptions import InvalidSignature from cryptography.exceptions import InvalidSignature
import hashlib import hashlib
from multiprocessing import Lock
import time import time
@dataclass @dataclass
@@ -13,6 +14,16 @@ class Transaction:
transaction_fee: int transaction_fee: int
signature: bytes 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): def is_valid(self):
sender_pubkey = Ed25519PublicKey.from_public_bytes(self.sender) sender_pubkey = Ed25519PublicKey.from_public_bytes(self.sender)
msg = self.id.to_bytes(4, "big") + \ msg = self.id.to_bytes(4, "big") + \
@@ -49,11 +60,32 @@ class Block:
difficulty_sum: int difficulty_sum: int
miner_pubkey: bytes miner_pubkey: bytes
transaction: Transaction transaction: Transaction
own_hash: bytes
balances: dict balances: dict
# (sender_pubkey, id) tuples # (sender_pubkey, id) tuples
used_transaction_ids: set used_transaction_ids: set
valid: bool 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): def validate(self, blockchain):
if self.transaction is not None: if self.transaction is not None:
if not self.transaction.is_valid(): if not self.transaction.is_valid():
@@ -83,9 +115,7 @@ class Block:
block_difficulty = max(calculated_difficulty, 2**28) block_difficulty = max(calculated_difficulty, 2**28)
if B_1_difficulty_sum + block_difficulty != self.difficulty_sum: if B_1_difficulty_sum + block_difficulty != self.difficulty_sum:
return False return False
block_raw = self.get_block_raw() self.valid = int.from_bytes(self.own_hash, "big") * block_difficulty < 2**256
block_hash = hashlib.sha256(block_raw).digest()
self.valid = int.from_bytes(block_hash, "big") * block_difficulty < 2**256
if self.valid: if self.valid:
self.calculate_balances(prev_block) self.calculate_balances(prev_block)
self.calculate_used_transaction_ids(prev_block) self.calculate_used_transaction_ids(prev_block)
@@ -141,5 +171,24 @@ class Blockchain:
def __init__(self): def __init__(self):
# maps block hashes to block instances # maps block hashes to block instances
self.__block_map = {} 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): def get_block(self, hash):
return self.__block_map.get(hash) with self.__lock:
return self.__block_map.get(hash)