def _validate_block_data(cls, block_data: dict): """ Validates the block_data dictionary. 'block_data' should be a strict subset of the 'block' dictionary, keys for all columns in the block table EXCEPT 'number' and 'hash'. If any validation fails, an exception is raised. For a block_data dictionary to be valid, it must: - Have a key for each block data column specified in BLOCK_DATA_COLS (at top of blocks.py) - BlockContender successfully validates with the Merkle root (meaning all signatures in the BlockContender can be verified using the Merkle root as the message) - Merkle leaves contained in BlockContender (block_contender.nodes) match Merkle leaves in block_data dict - Merkle root is correct root if a Merkle tree is built from Merkle leaves - Masternode signature is valid (signature is valid using Merkle root as message and masternode_vk as vk) :param block_data: The dictionary containing a key for each column in BLOCK_DATA_COLS (ie 'merkle_root', 'prev_block_hash', .. ect) :raises: An BlockStorageValidationException (or subclass) if any validation fails """ # Check block_data has all the necessary keys expected_keys = set(BLOCK_DATA_COLS.keys()) actual_keys = set(block_data.keys()) missing_keys = expected_keys - actual_keys extra_keys = actual_keys - expected_keys # Check for missing keys if len(missing_keys) > 0: raise BlockStorageValidationException( "block_data keys {} missing key(s) {}".format( actual_keys, missing_keys)) # Check for extra (unrecognized) keys if len(extra_keys) > 0: raise BlockStorageValidationException( "block_data keys {} has unrecognized keys {}".format( actual_keys, extra_keys)) # Validate Merkle Tree tree = MerkleTree.from_leaves_hex_str(block_data['merkle_leaves']) if tree.root_as_hex != block_data['merkle_root']: raise InvalidMerkleTreeException( "Merkle Tree could not be validated for block_data {}".format( block_data)) # Validate BlockContender nodes match merkle leaves block_leaves = block_data['block_contender'].merkle_leaves if len(block_leaves) != len(tree.leaves): raise InvalidBlockContenderException( "Number of Merkle leaves on BlockContender {} does not match number of" " leaves in MerkleTree {}".format(len(block_leaves), len(tree.leaves))) for block_leaf, merkle_leaf in zip(block_leaves, tree.leaves_as_hex): if block_leaf != merkle_leaf: raise InvalidBlockContenderException( "BlockContender leaves do not match Merkle leaves\nblock leaves = " "{}\nmerkle leaves = {}".format(block_leaves, tree.leaves_as_hex)) # Validate MerkleSignatures inside BlockContender match Merkle leaves from raw transactions bc = block_data['block_contender'] if not bc.validate_signatures(): raise InvalidBlockContenderException( "BlockContender signatures could not be validated! BC = {}". format(bc)) # TODO validate MerkleSignatures are infact signed by valid delegates # this is tricky b/c we would need to know who the delegates were at the time of the block, not necessarily the # current delegates # Validate Masternode Signature if not is_valid_hex(block_data['masternode_vk'], length=64): raise InvalidBlockSignatureException( "Invalid verifying key for field masternode_vk: {}".format( block_data['masternode_vk'])) if not ED25519Wallet.verify(block_data['masternode_vk'], bytes.fromhex(block_data['merkle_root']), block_data['masternode_signature']): raise InvalidBlockSignatureException( "Could not validate Masternode's signature on block data")
def verify_signature(future): signature, verifying_key = future.result() if ED25519Wallet.verify(verifying_key, self.merkle, signature): self.signatures.append(future.result())