def __init__(self, left, right, hash: str = None): self.left = left self.right = right if hash is None and left is not None and right is not None: self.hash = Hasher.hash(left.hash + right.hash) else: self.hash = hash
def construct(self, items: list, size): if size is None: size = len(items) layer = [MerkleNode(None, None, Hasher.object_hash(items[x])) for x in range(size)] self.number_of_nodes += len(layer) self.number_of_hashs += len(layer) while len(layer) > 1: if len(layer) & 1 == 1: # add an extra null node layer.append(MerkleNode(None, None, "")) self.number_of_nodes += 1 up_layer = [] for i in range(0, len(layer) - 1, 2): up_layer.append(MerkleNode(layer[i], layer[i + 1])) self.number_of_nodes += int(len(layer) / 2) self.number_of_hashs += int(len(layer) / 2) layer = up_layer # return the root if len(layer) == 1: return layer[0] else: self.number_of_nodes += 1 return MerkleNode(None, None, "")
def verify_chain(block_headers: list, transactions: list): """ Verify if a given chain is valid. :param block_headers: list of block headers :param transactions: list of transactions of each block :return: True if the given chain is valid """ if len(block_headers) != len(transactions) and len(block_headers) == 0: return False # an valid chain contains only the genesis block if len(block_headers) == 1: return True # validate the all the rest of blocks for i in range(len(block_headers)): # check if the block links to the previous block except the genesis block if i > 0: if block_headers[i].previous_hash != Hasher.object_hash(block_headers[i-1]): return False # create transaction merkle tree and get the root if block_headers[i].transaction_root != ZeroMerkleTree(transactions[i]).root_hash: return False # verify if the proof of work is correct if not ZeroChain.proof_pow(block_headers[i]): return False # return True if all blcoks are fine return True
def ZeroMerkleTreeLite(items: list, size = None): if size is None: size = len(items) layer = [Hasher.raw_hash(items[x]) for x in range(size)] items = len(layer) while items > 1: for i in range(0, items - 1, 2): layer[i>>1] = Hasher.raw_hash(layer[i], layer[i + 1]) if items & 1 == 1: # move the last odd item to the upper layer layer[(items+1)>>1] = layer[items-1] items = (items+1)>>1 # return the root if items == 1: return layer[0] else: return b""
def proof_pow(block_header): """ Validates the block_header :param block_header: :returns True if the block_header is a valid pow. """ difficulty = block_header.difficulty return Hasher.object_hash(block_header)[:difficulty] == "0" * difficulty
def LibraMerkleTreeLite(items: list, size = None): if size is None: size = len(items) layer = [Hasher.raw_hash(items[x]) for x in range(size)] if len(layer) & 1 == 1: layer.append(b"") items = len(layer) while items > 1: if items & 1 == 1: layer[items] = b"" items += 1 for i in range(0, items, 2): layer[i>>1] = Hasher.raw_hash(layer[i], layer[i + 1]) items = (items+1)>>1 # return the root if items == 1: return layer[0] else: return b""
def create_block(self): """ Creates a block and include all transactions in self.pending_transactions. :returns the new created block_header """ # create transaction merkle tree and get the root transaction_tree = ZeroMerkleTree(self.pending_transactions) transaction_root = transaction_tree.root_hash block_header = BlockHeader(height = self.block_height, previous_hash = Hasher.object_hash(self.latest_block), transaction_root = transaction_root, difficulty = self.difficulty, nonce = 0) self.pow_add_block(block_header) return block_header