Implement gambling
This commit is contained in:
358
blockchain.py
358
blockchain.py
@@ -5,8 +5,23 @@ import hashlib
|
||||
from multiprocessing import Lock
|
||||
import time
|
||||
|
||||
@dataclass
|
||||
n = 22152137184697602751949152182712806144286735269755991212091578018969267364854563246965161398309375840488156997640625085213985729183180764348127989435514689722834129288342499703533613231239853168289771769536412763137391054558055082146752229593979328251181647873233949602834141648160681711983351545692646009424518816069561938917629523175464947983950548802679152115205735609960641453864298194702935993896839374645356040490091081577992299773430144650589605043643969140352237968606446474316247592579560197155686719175897498255683642121505357781103123719079205647707696181709515150954235402701095586525936356219917713227143
|
||||
|
||||
class Transaction:
|
||||
pass
|
||||
|
||||
class NoTransaction(Transaction):
|
||||
def is_valid(self):
|
||||
return True
|
||||
def is_valid_after_block(self, block):
|
||||
return True
|
||||
def get_transaction_raw(self):
|
||||
return 149 * b"\0"
|
||||
def is_empty(self):
|
||||
return True
|
||||
|
||||
@dataclass
|
||||
class PaymentTransaction(Transaction):
|
||||
id: int
|
||||
sender: bytes
|
||||
receiver: bytes
|
||||
@@ -15,18 +30,18 @@ class Transaction:
|
||||
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],
|
||||
return PaymentTransaction(
|
||||
id = int.from_bytes(transaction_raw[1:5], "big"),
|
||||
sender = transaction_raw[5:37],
|
||||
receiver = transaction_raw[37:69],
|
||||
amount = int.from_bytes(transaction_raw[69:77], "big"),
|
||||
transaction_fee = int.from_bytes(transaction_raw[77:85], "big"),
|
||||
signature = transaction_raw[85:149],
|
||||
)
|
||||
def is_valid(self):
|
||||
sender_pubkey = Ed25519PublicKey.from_public_bytes(self.sender)
|
||||
msg = self.id.to_bytes(4, "big") + \
|
||||
msg = b"\x01" + \
|
||||
self.id.to_bytes(4, "big") + \
|
||||
self.sender + \
|
||||
self.receiver + \
|
||||
self.amount.to_bytes(8, "big") + \
|
||||
@@ -44,18 +59,178 @@ class Transaction:
|
||||
return False
|
||||
return balance >= self.amount + self.transaction_fee
|
||||
def get_transaction_raw(self):
|
||||
return self.id.to_bytes(4, "big") + \
|
||||
return b"\x01" + \
|
||||
self.id.to_bytes(4, "big") + \
|
||||
self.sender + \
|
||||
self.receiver + \
|
||||
self.amount.to_bytes(8, "big") + \
|
||||
self.transaction_fee.to_bytes(8, "big") + \
|
||||
self.signature
|
||||
def open_transactions_hash_data(self):
|
||||
return b"\0" + \
|
||||
self.transaction_fee.to_bytes(8, "big") + \
|
||||
self.amount.to_bytes(8, "big") + \
|
||||
self.sender + \
|
||||
self.id.to_bytes(4, "big")
|
||||
def sorting_id(self):
|
||||
return (-self.transaction_fee, self.sender, self.id)
|
||||
return (1, -self.transaction_fee, -self.amount, self.sender, self.id)
|
||||
def is_empty(self):
|
||||
return False
|
||||
def __eq__(self, other):
|
||||
return (self.id, self.sender, self.receiver, self.amount, self.transaction_fee) == \
|
||||
return isinstance(other, PaymentTransaction) \
|
||||
and (self.id, self.sender, self.receiver, self.amount, self.transaction_fee) == \
|
||||
(other.id, other.sender, other.receiver, other.amount, other.transaction_fee)
|
||||
|
||||
@dataclass
|
||||
class GamblingTransaction(Transaction):
|
||||
id: int
|
||||
player: bytes
|
||||
amount: int
|
||||
transaction_fee: int
|
||||
signature: bytes
|
||||
|
||||
def from_bytes(transaction_raw):
|
||||
if transaction_raw[117:149] != 32 * b"\0":
|
||||
return InvalidTransaction()
|
||||
return GamblingTransaction(
|
||||
id = int.from_bytes(transaction_raw[1:5], "big"),
|
||||
player = transaction_raw[5:37],
|
||||
amount = int.from_bytes(transaction_raw[37:45], "big"),
|
||||
transaction_fee = int.from_bytes(transaction_raw[45:53], "big"),
|
||||
signature = transaction_raw[53:117],
|
||||
)
|
||||
def is_valid(self):
|
||||
player_pubkey = Ed25519PublicKey.from_public_bytes(self.player)
|
||||
msg = b"\x02" + \
|
||||
self.id.to_bytes(4, "big") + \
|
||||
self.player + \
|
||||
self.amount.to_bytes(8, "big") + \
|
||||
self.transaction_fee.to_bytes(8, "big")
|
||||
try:
|
||||
player_pubkey.verify(self.signature, msg)
|
||||
except InvalidSignature:
|
||||
return False
|
||||
return self.amount >= 1
|
||||
def is_valid_after_block(self, block):
|
||||
if (self.player, self.id) in block.used_transaction_ids:
|
||||
return False
|
||||
balance = block.balances.get(self.player)
|
||||
if balance is None:
|
||||
return False
|
||||
return balance >= self.amount + self.transaction_fee
|
||||
def get_transaction_raw(self):
|
||||
return b"\x02" + \
|
||||
self.id.to_bytes(4, "big") + \
|
||||
self.player + \
|
||||
self.amount.to_bytes(8, "big") + \
|
||||
self.transaction_fee.to_bytes(8, "big") + \
|
||||
self.signature + \
|
||||
32 * b"\0"
|
||||
def open_transactions_hash_data(self):
|
||||
return b"\0" + \
|
||||
self.transaction_fee.to_bytes(8, "big") + \
|
||||
self.amount.to_bytes(8, "big") + \
|
||||
self.player + \
|
||||
self.id.to_bytes(4, "big")
|
||||
def sorting_id(self):
|
||||
return (1, -self.transaction_fee, -self.amount, self.player, self.id)
|
||||
def is_empty(self):
|
||||
return False
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, GamblingTransaction) \
|
||||
and (self.id, self.player, self.amount, self.transaction_fee) == \
|
||||
(other.id, other.player, other.amount, other.transaction_fee)
|
||||
|
||||
def is_valid_group_element(x):
|
||||
return x > 0 and x <= n//2
|
||||
|
||||
def normalize(x):
|
||||
if x <= n//2:
|
||||
return x
|
||||
return n - x
|
||||
|
||||
@dataclass
|
||||
class RevealTransaction:
|
||||
revealer_pubkey: bytes
|
||||
associated_proof_hash: bytes
|
||||
reveal_value: bytes
|
||||
intermediates: list
|
||||
|
||||
def from_bytes(transaction_raw, associated_proof_data):
|
||||
if transaction_raw[65:149] != 84 * b"\0":
|
||||
return InvalidTransaction()
|
||||
return RevealTransaction(
|
||||
revealer_pubkey = transaction_raw[1:33],
|
||||
associated_proof_hash = transaction_raw[33:65],
|
||||
reveal_value = associated_proof_data[0:256],
|
||||
intermediates = [associated_proof_data[(i+1)*256:(i+2)*256] for i in range(20)],
|
||||
)
|
||||
def is_valid(self):
|
||||
to_hash = self.get_associated_data()
|
||||
return hashlib.sha256(to_hash).digest() == self.associated_proof_hash
|
||||
def is_valid_after_block(self, block):
|
||||
if len(block.pending_commitment_blocks) == 0:
|
||||
return False
|
||||
claim_R = int.from_bytes(self.reveal_value, "big")
|
||||
if not is_valid_group_element(claim_R):
|
||||
return False
|
||||
intermediate_numbers = [int.from_bytes(i, "big") for i in self.intermediates]
|
||||
for intermediate in intermediate_numbers:
|
||||
if not is_valid_group_element(intermediate):
|
||||
return False
|
||||
claim_H = int.from_bytes(block.pending_commitment_blocks[0][0], "big")
|
||||
for c in range(20):
|
||||
i = 30 - c
|
||||
claim_I = intermediate_numbers[c]
|
||||
to_hash = self.revealer_pubkey + \
|
||||
claim_H.to_bytes(256, "big") + \
|
||||
claim_I.to_bytes(256, "big") + \
|
||||
claim_R.to_bytes(256, "big") + \
|
||||
i.to_bytes(1, "big")
|
||||
e = int.from_bytes(hashlib.sha256(to_hash).digest(), "big")
|
||||
new_H = normalize((claim_H * pow(claim_I, e, n)) % n)
|
||||
new_R = normalize((claim_I * pow(claim_R, e, n)) % n)
|
||||
claim_H = new_H
|
||||
claim_R = new_R
|
||||
return normalize(pow(claim_H, 2**1024, n)) == claim_R
|
||||
def get_transaction_raw(self):
|
||||
return b"\x03" + \
|
||||
self.revealer_pubkey + \
|
||||
self.associated_proof_hash + \
|
||||
84 * b"\0"
|
||||
def open_transactions_hash_data(self):
|
||||
return b"\x01" + 52 * b"\0"
|
||||
def get_associated_data(self):
|
||||
return b"".join([self.reveal_value] + self.intermediates)
|
||||
def sorting_id(self):
|
||||
return (0,)
|
||||
def is_empty(self):
|
||||
return False
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, RevealTransaction) \
|
||||
and (self.revealer_pubkey, self.associated_proof_hash, self.reveal_value, self.intermediates) == \
|
||||
(other.revealer_pubkey, other.associated_proof_hash, other.reveal_value, other.intermediates)
|
||||
|
||||
class InvalidTransaction:
|
||||
def is_valid(self):
|
||||
return False
|
||||
|
||||
def associated_data_required(transaction):
|
||||
return transaction[0] == 3 and transaction[65:149] == 84 * b"\0"
|
||||
|
||||
def transaction_from_bytes(transaction_raw, associated_data = None):
|
||||
assert len(transaction_raw) == 149
|
||||
if transaction_raw == 149 * b"\0":
|
||||
return NoTransaction()
|
||||
elif transaction_raw[0] == 1:
|
||||
return PaymentTransaction.from_bytes(transaction_raw)
|
||||
elif transaction_raw[0] == 2:
|
||||
return GamblingTransaction.from_bytes(transaction_raw)
|
||||
elif transaction_raw[0] == 3:
|
||||
return RevealTransaction.from_bytes(transaction_raw, associated_data)
|
||||
else:
|
||||
return InvalidTransaction()
|
||||
|
||||
@dataclass
|
||||
class Block:
|
||||
nonce: int
|
||||
@@ -66,37 +241,39 @@ class Block:
|
||||
miner_pubkey: bytes
|
||||
transaction: Transaction
|
||||
own_hash: bytes
|
||||
pending_commitment_blocks: list
|
||||
pending_gambling_transactions: list
|
||||
balances: dict
|
||||
# (sender_pubkey, id) tuples
|
||||
used_transaction_ids: set
|
||||
block_number: int
|
||||
persist_address: int
|
||||
valid: bool
|
||||
|
||||
def from_bytes(block_raw):
|
||||
assert len(block_raw) == 292
|
||||
transaction_raw = block_raw[0:148]
|
||||
if transaction_raw == 148 * b"\0":
|
||||
transaction = None
|
||||
else:
|
||||
transaction = Transaction.from_bytes(transaction_raw)
|
||||
def from_bytes(block_raw, associated_data = None):
|
||||
assert len(block_raw) == 293
|
||||
transaction_raw = block_raw[0:149]
|
||||
transaction = transaction_from_bytes(transaction_raw, associated_data)
|
||||
return Block(
|
||||
transaction = transaction,
|
||||
message = block_raw[148:180],
|
||||
miner_pubkey = block_raw[180:212],
|
||||
previous_hash = block_raw[212:244],
|
||||
timestamp = int.from_bytes(block_raw[244:252], "big"),
|
||||
difficulty_sum = int.from_bytes(block_raw[252:284], "big"),
|
||||
nonce = int.from_bytes(block_raw[284:292], "big"),
|
||||
message = block_raw[149:181],
|
||||
miner_pubkey = block_raw[181:213],
|
||||
previous_hash = block_raw[213:245],
|
||||
timestamp = int.from_bytes(block_raw[245:253], "big"),
|
||||
difficulty_sum = int.from_bytes(block_raw[253:285], "big"),
|
||||
nonce = int.from_bytes(block_raw[285:293], "big"),
|
||||
own_hash = hashlib.sha256(block_raw).digest(),
|
||||
pending_commitment_blocks = None,
|
||||
pending_gambling_transactions = None,
|
||||
balances = None,
|
||||
used_transaction_ids = None,
|
||||
block_number = None,
|
||||
persist_address = None,
|
||||
valid = False,
|
||||
)
|
||||
def validate(self, blockchain):
|
||||
if self.transaction is not None:
|
||||
if not self.transaction.is_valid():
|
||||
return False
|
||||
if not self.transaction.is_valid():
|
||||
return False
|
||||
if self.previous_hash != 32 * b"\0":
|
||||
prev_block = blockchain.get_block(self.previous_hash)
|
||||
if prev_block is None:
|
||||
@@ -107,11 +284,11 @@ class Block:
|
||||
return False
|
||||
if self.timestamp > time.time():
|
||||
return False
|
||||
if self.transaction is not None and not self.transaction.is_valid_after_block(prev_block):
|
||||
if not self.transaction.is_valid_after_block(prev_block):
|
||||
return False
|
||||
else:
|
||||
prev_block = None
|
||||
if self.transaction is not None:
|
||||
if not self.transaction.is_empty():
|
||||
return False
|
||||
# check for the correct miner pubkey - which will become public at launch day
|
||||
h = hashlib.sha256(self.miner_pubkey).hexdigest()
|
||||
@@ -127,10 +304,28 @@ class Block:
|
||||
return False
|
||||
self.valid = int.from_bytes(self.own_hash, "big") * block_difficulty < 2**256
|
||||
if self.valid:
|
||||
self.calculate_block_number(prev_block)
|
||||
self.calculate_pending_gambling_transactions(prev_block)
|
||||
self.calculate_balances(prev_block)
|
||||
self.calculate_used_transaction_ids(prev_block)
|
||||
self.calculate_block_number(prev_block)
|
||||
self.calculate_persist_address(prev_block)
|
||||
return self.valid
|
||||
def calculate_pending_gambling_transactions(self, prev_block):
|
||||
if prev_block is None:
|
||||
self.pending_commitment_blocks = []
|
||||
self.pending_gambling_transactions = []
|
||||
return
|
||||
pending_commitment_blocks = prev_block.pending_commitment_blocks.copy()
|
||||
pending_gambling_transactions = prev_block.pending_gambling_transactions.copy()
|
||||
if isinstance(self.transaction, GamblingTransaction):
|
||||
pending_gambling_transactions.append(self.transaction)
|
||||
if self.block_number % 256 == 255:
|
||||
pending_commitment_blocks.append((self.own_hash, pending_gambling_transactions))
|
||||
pending_gambling_transactions = []
|
||||
if isinstance(self.transaction, RevealTransaction):
|
||||
pending_commitment_blocks = pending_commitment_blocks[1:]
|
||||
self.pending_commitment_blocks = pending_commitment_blocks
|
||||
self.pending_gambling_transactions = pending_gambling_transactions
|
||||
def calculate_balances(self, prev_block):
|
||||
if prev_block is None:
|
||||
self.balances = {
|
||||
@@ -139,13 +334,29 @@ class Block:
|
||||
return
|
||||
balances = prev_block.balances.copy()
|
||||
balances.setdefault(self.miner_pubkey, 0)
|
||||
balances.setdefault(t.receiver, 0)
|
||||
balances[self.miner_pubkey] += 100
|
||||
t = self.transaction
|
||||
if t is not None:
|
||||
if isinstance(t, PaymentTransaction):
|
||||
balances[self.miner_pubkey] += t.transaction_fee
|
||||
balances[t.sender] -= (t.amount + t.transaction_fee)
|
||||
balances.setdefault(t.receiver, 0)
|
||||
balances[t.receiver] += t.amount
|
||||
elif isinstance(t, GamblingTransaction):
|
||||
balances[self.miner_pubkey] += t.transaction_fee
|
||||
balances[t.player] -= (t.amount + t.transaction_fee)
|
||||
elif isinstance(t, RevealTransaction):
|
||||
balances[self.miner_pubkey] += 100
|
||||
balances.setdefault(t.revealer_pubkey, 0)
|
||||
balances[t.revealer_pubkey] += 1500
|
||||
revealed_gamblings = prev_block.pending_commitment_blocks[0][1]
|
||||
for transaction in revealed_gamblings:
|
||||
to_hash = transaction.id.to_bytes(4, "big") + \
|
||||
transaction.player + \
|
||||
t.reveal_value
|
||||
h = hashlib.sha256(to_hash).digest()
|
||||
if h[0] < 0x80:
|
||||
continue
|
||||
balances[transaction.player] += 2 * transaction.amount
|
||||
self.balances = balances
|
||||
def calculate_used_transaction_ids(self, prev_block):
|
||||
if prev_block is None:
|
||||
@@ -153,14 +364,23 @@ class Block:
|
||||
return
|
||||
used_transaction_ids = prev_block.used_transaction_ids.copy()
|
||||
t = self.transaction
|
||||
if t is not None:
|
||||
if isinstance(t, PaymentTransaction):
|
||||
used_transaction_ids.add((t.sender, t.id))
|
||||
elif isinstance(t, GamblingTransaction):
|
||||
used_transaction_ids.add((t.player, t.id))
|
||||
self.used_transaction_ids = used_transaction_ids
|
||||
def calculate_block_number(self, prev_block):
|
||||
if prev_block is None:
|
||||
self.block_number = 0
|
||||
else:
|
||||
self.block_number = prev_block.block_number + 1
|
||||
def calculate_persist_address(self, prev_block):
|
||||
if prev_block is None:
|
||||
self.persist_address = 0
|
||||
else:
|
||||
self.persist_address = prev_block.persist_address + 293
|
||||
if isinstance(prev_block.transaction, RevealTransaction):
|
||||
self.persist_address += 5376
|
||||
def get_difficulty_info(self, steps, blockchain):
|
||||
if steps == 0:
|
||||
return self.difficulty_sum, self.timestamp
|
||||
@@ -172,11 +392,7 @@ class Block:
|
||||
previous_block = blockchain.get_block(self.previous_hash)
|
||||
return previous_block.get_difficulty_info(steps-1, blockchain)
|
||||
def get_block_raw(self):
|
||||
if self.transaction is None:
|
||||
transaction = 148 * b"\0"
|
||||
else:
|
||||
transaction = self.transaction.get_transaction_raw()
|
||||
return transaction + \
|
||||
return self.transaction.get_transaction_raw() + \
|
||||
self.message + \
|
||||
self.miner_pubkey + \
|
||||
self.previous_hash + \
|
||||
@@ -216,12 +432,12 @@ class OpenTransactions:
|
||||
return None
|
||||
return self.__open_transactions[i]
|
||||
def __has_space(self, transaction):
|
||||
if len(self.__open_transactions) < 1000:
|
||||
if len(self.__open_transactions) < 1024:
|
||||
return True
|
||||
return transaction.sorting_id() < self.__open_transactions[-1].sorting_id()
|
||||
def __cleanup(self):
|
||||
# sort everything
|
||||
self.__open_transactions.sort(key = Transaction.sorting_id)
|
||||
self.__open_transactions.sort(key = lambda t: t.sorting_id())
|
||||
# drop out invalid ones
|
||||
# - reused ids
|
||||
# - paying more money than available
|
||||
@@ -232,15 +448,30 @@ class OpenTransactions:
|
||||
return
|
||||
used_transaction_ids = latest_block.used_transaction_ids.copy()
|
||||
balances = latest_block.balances.copy()
|
||||
contains_reveal_transaction = False
|
||||
def is_valid(transaction):
|
||||
sender_tuple = (transaction.sender, transaction.id)
|
||||
nonlocal contains_reveal_transaction
|
||||
if isinstance(transaction, PaymentTransaction):
|
||||
sender_tuple = (transaction.sender, transaction.id)
|
||||
elif isinstance(transaction, GamblingTransaction):
|
||||
sender_tuple = (transaction.player, transaction.id)
|
||||
elif isinstance(transaction, RevealTransaction):
|
||||
latest_block = self.__blockchain.get_latest_block()
|
||||
if latest_block is None:
|
||||
return False
|
||||
if not transaction.is_valid_after_block(latest_block):
|
||||
return False
|
||||
if contains_reveal_transaction:
|
||||
return False
|
||||
contains_reveal_transaction = True
|
||||
return True
|
||||
if sender_tuple in used_transaction_ids:
|
||||
return False
|
||||
balance = balances.get(transaction.sender) or 0
|
||||
balance = balances.get(sender_tuple[0]) or 0
|
||||
if transaction.amount + transaction.transaction_fee > balance:
|
||||
return False
|
||||
used_transaction_ids.add(sender_tuple)
|
||||
balances[transaction.sender] = balance - transaction.amount - transaction.transaction_fee
|
||||
balances[sender_tuple[0]] = balance - transaction.amount - transaction.transaction_fee
|
||||
return True
|
||||
self.__open_transactions = [transaction for transaction in self.__open_transactions if is_valid(transaction)]
|
||||
# limit to 1024
|
||||
@@ -251,12 +482,10 @@ class OpenTransactions:
|
||||
current_hash = 32 * b"\0"
|
||||
for i in range(1024):
|
||||
if i >= len(self.__open_transactions):
|
||||
transaction_data = 44 * b"\0"
|
||||
transaction_data = 53 * b"\0"
|
||||
else:
|
||||
transaction = self.__open_transactions[i]
|
||||
transaction_data = transaction.transaction_fee.to_bytes(8, "big") + \
|
||||
transaction.sender + \
|
||||
transaction.id.to_bytes(4, "big")
|
||||
transaction_data = transaction.open_transactions_hash_data()
|
||||
current_hash = hashlib.sha256(current_hash + transaction_data).digest()
|
||||
self.__hashes.append(current_hash)
|
||||
|
||||
@@ -265,6 +494,7 @@ class Blockchain:
|
||||
# maps block hashes to block instances
|
||||
self.__block_map = {}
|
||||
self.__latest_block_hash = None
|
||||
self.__associated_data = {}
|
||||
self.__lock = Lock()
|
||||
self.open_transactions = OpenTransactions(self)
|
||||
self.__load_blocks_from_disk()
|
||||
@@ -273,10 +503,16 @@ class Blockchain:
|
||||
try:
|
||||
with open("blockchain", "rb") as f:
|
||||
while True:
|
||||
block = f.read(292)
|
||||
if len(block) < 292:
|
||||
block = f.read(293)
|
||||
if len(block) < 293:
|
||||
break
|
||||
block_obj = self.add_block(block)
|
||||
if associated_data_required(block[0:149]):
|
||||
associated_data = f.read(5376)
|
||||
if len(associated_data) < 5376:
|
||||
break
|
||||
else:
|
||||
associated_data = None
|
||||
block_obj = self.add_block(block, associated_data)
|
||||
if not block_obj.validate(self):
|
||||
break
|
||||
last_valid = block_obj
|
||||
@@ -319,16 +555,18 @@ class Blockchain:
|
||||
new_block = self.__block_map[new_block.previous_hash]
|
||||
if old_block is not None and old_block.block_number > new_block.block_number:
|
||||
old_block = self.__block_map[old_block.previous_hash]
|
||||
start_block_number = block_list[-1].block_number
|
||||
start_addr = start_block_number * 292
|
||||
start_addr = block_list[-1].persist_address
|
||||
open_mode = "wb" if start_addr == 0 else "r+b"
|
||||
with open("blockchain", open_mode) as f:
|
||||
f.seek(start_addr)
|
||||
for block in reversed(block_list):
|
||||
f.write(block.get_block_raw())
|
||||
def add_block(self, block_raw):
|
||||
if isinstance(block.transaction, RevealTransaction):
|
||||
f.write(block.transaction.get_associated_data())
|
||||
f.truncate()
|
||||
def add_block(self, block_raw, associated_data = None):
|
||||
with self.__lock:
|
||||
block = Block.from_bytes(block_raw)
|
||||
block = Block.from_bytes(block_raw, associated_data)
|
||||
if block.own_hash not in self.__block_map:
|
||||
self.__block_map[block.own_hash] = block
|
||||
return self.__block_map[block.own_hash]
|
||||
@@ -347,3 +585,11 @@ class Blockchain:
|
||||
if self.__latest_block_hash is None:
|
||||
return None
|
||||
return self.__block_map[self.__latest_block_hash]
|
||||
def cache_associated_data(self, transaction):
|
||||
if not isinstance(transaction, RevealTransaction):
|
||||
return
|
||||
with self.__lock:
|
||||
self.__associated_data[transaction.associated_proof_hash] = transaction.get_associated_data()
|
||||
def get_associated_data(self, associated_proof_hash):
|
||||
with self.__lock:
|
||||
return self.__associated_data.get(associated_proof_hash, None)
|
||||
|
||||
Reference in New Issue
Block a user