Implement block transfer logic

This commit is contained in:
2024-03-16 21:56:12 +01:00
parent 44598fc030
commit f41710c3dd
3 changed files with 177 additions and 41 deletions

View File

@@ -17,12 +17,12 @@ class Transaction:
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],
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)
@@ -66,25 +66,25 @@ class Block:
used_transaction_ids: set
valid: bool
def from_bytes(self, block_raw):
def from_bytes(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,
return 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:
@@ -92,15 +92,18 @@ class Block:
return False
if self.previous_hash != 32 * b"\0":
prev_block = blockchain.get_block(self.previous_hash)
if prev_block is None:
return False
if not prev_block.valid:
return False
if self.timestamp <= prev_block.timestamp:
return False
if self.timestamp > time.time():
return False
if not self.transaction.is_valid_after_block(prev_block):
if self.transaction is not None and not self.transaction.is_valid_after_block(prev_block):
return False
else:
prev_block = None
if self.transaction is not None:
return False
# check for the correct miner pubkey - which will become public at launch day
@@ -128,10 +131,10 @@ class Block:
return
balances = prev_block.balances.copy()
balances.setdefault(self.miner_pubkey, 0)
balances[miner_pubkey] += 100
balances[self.miner_pubkey] += 100
t = self.transaction
if t is not None:
balances[miner_pubkey] += t.transaction_fee
balances[self.miner_pubkey] += t.transaction_fee
balances[t.sender] -= (t.amount + t.transaction_fee)
balances[t.receiver] += t.amount
self.balances = balances
@@ -174,21 +177,41 @@ class Blockchain:
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)
new_block = self.get_block(block_hash)
assert new_block is not None
assert new_block.valid
while True:
with self.__lock:
latest_block_hash = self.__latest_block_hash
if latest_block_hash is not None:
latest_block = self.get_block(latest_block_hash)
current_difficulty_sum = latest_block.get_difficulty_info(1, self)[0]
new_difficulty_sum = new_block.get_difficulty_info(1, self)[0]
if new_difficulty_sum <= current_difficulty_sum:
return
self.__latest_block_hash = block_hash
return False
with self.__lock:
if self.__latest_block_hash != latest_block_hash:
continue
self.__latest_block_hash = block_hash
return True
def add_block(self, block_raw):
with self.__lock:
block = Block.from_bytes(block_raw)
self.__block_map[block.own_hash] = block
return block
if block.own_hash not in self.__block_map:
self.__block_map[block.own_hash] = block
return self.__block_map[block.own_hash]
def get_block(self, hash):
with self.__lock:
return self.__block_map.get(hash)
def get_second_last_difficulty_sum(self):
with self.__lock:
latest_block_hash = self.__latest_block_hash
if latest_block_hash is None:
return 0
block = self.get_block(latest_block_hash)
return block.get_difficulty_info(1, self)[0]
def get_latest_block(self):
with self.__lock:
if self.__latest_block_hash is None:
return None
return self.__block_map[self.__latest_block_hash]