def new_block_procedure(self, block, txs): self.log.critical( "\n***\nDONE COLLECTING BLOCK DATA FROM NODES. Storing new block.\n***\n" ) hash_of_nodes = MerkleTree.hash_nodes(block.nodes) tree = b"".join(block.nodes).hex() signatures = "".join( [merk_sig.signature for merk_sig in block.signatures]) # Store the block + transaction data block_num = -1 with DB() as db: tables = db.tables q = insert(tables.blocks).values(hash=hash_of_nodes, tree=tree, signatures=signatures) q_result = db.execute(q) block_num = q_result.lastrowid for key, value in txs.items(): tx = {'key': key, 'value': value} qq = insert(tables.transactions).values(tx) db.execute(qq) assert block_num > 0, "Block num must be greater than 0! Was it not set in the DB() context session?" # Notify delegates of new block self.log.info( "Masternode sending NewBlockNotification to delegates with new block hash {} and block num {}" .format(hash_of_nodes, block_num)) notif = NewBlockNotification.create(new_block_hash=hash_of_nodes.hex(), new_block_num=block_num) self.parent.composer.send_pub_msg( filter=Constants.ZmqFilters.MasternodeDelegate, message=notif)
def _validate_sigs(self, block: BlockContender) -> bool: signatures = block.signatures msg = MerkleTree.hash_nodes(block.merkle_leaves) for sig in signatures: # TODO -- ensure that the sender belongs to the top delegate pool self.log.debug("mn verifying signature: {}".format(sig)) if not sig.verify(msg, sig.sender): self.log.error("Masternode could not verify signature!!! Sig={}".format(sig)) return False return True
def validate_block_contender(self, block: BlockContender) -> bool: """ Helper method to validate a block contender. For a block contender to be valid it must: 1) Have a provable merkle tree, ie. all nodes must be hash of (left child + right child) 2) Be signed by at least 2/3 of the top 32 delegates :param block_contender: The BlockContender to validate :return: True if the BlockContender is valid, false otherwise """ def _validate_sigs(signatures, msg) -> bool: for sig in signatures: self.log.info("mn verifying signature: {}".format(sig)) if not sig.verify(msg, sig.sender): self.log.error( "!!!! Oh no why couldnt we verify sig {}???".format( sig)) return False return True # Development sanity checks (these should be removed in production) assert len( block.nodes ) >= 1, "Masternode got block contender with no nodes! {}".format( block) assert len(block.signatures) >= Constants.Testnet.Majority, \ "Received a block contender with only {} signatures (which is less than a majority of {}"\ .format(len(block.signatures), Constants.Testnet.Majority) # TODO -- ensure that this block contender's previous block is this Masternode's current block... # Prove Merkle Tree hash_of_nodes = MerkleTree.hash_nodes(block.nodes) tx_hashes = block.nodes[len(block.nodes) // 2:] if not MerkleTree.verify_tree(tx_hashes, hash_of_nodes): self.log.error( "\n\n\n\nCOULD NOT VERIFY MERKLE TREE FOR BLOCK CONTENDER {}\n\n\n" .format(block)) return False # Validate signatures if not _validate_sigs(block.signatures, hash_of_nodes): self.log.error( "MN COULD NOT VALIDATE SIGNATURES FOR CONTENDER {}".format( block)) return False return True