def validate_additions( coins: List[Tuple[bytes32, List[Coin]]], proofs: Optional[List[Tuple[bytes32, bytes, Optional[bytes]]]], root, ): if proofs is None: # Verify root additions_merkle_set = MerkleSet() # Addition Merkle set contains puzzlehash and hash of all coins with that puzzlehash for puzzle_hash, coins_l in coins: additions_merkle_set.add_already_hashed(puzzle_hash) additions_merkle_set.add_already_hashed(hash_coin_list(coins_l)) additions_root = additions_merkle_set.get_root() if root != additions_root: return False else: for i in range(len(coins)): assert coins[i][0] == proofs[i][0] coin_list_1: List[Coin] = coins[i][1] puzzle_hash_proof: Optional[bytes] = proofs[i][1] coin_list_proof: Optional[bytes] = proofs[i][2] if len(coin_list_1) == 0: # Verify exclusion proof for puzzle hash assert puzzle_hash_proof is not None not_included = confirm_not_included_already_hashed( root, coins[i][0], puzzle_hash_proof, ) if not_included is False: return False else: try: # Verify inclusion proof for coin list assert coin_list_proof is not None included = confirm_included_already_hashed( root, hash_coin_list(coin_list_1), coin_list_proof, ) if included is False: return False except AssertionError: return False try: # Verify inclusion proof for puzzle hash assert puzzle_hash_proof is not None included = confirm_included_already_hashed( root, coins[i][0], puzzle_hash_proof, ) if included is False: return False except AssertionError: return False return True
async def test_basics(self): num_blocks = 20 blocks = bt.get_consecutive_blocks(num_blocks) merkle_set = MerkleSet() merkle_set_reverse = MerkleSet() coins = list( itertools.chain.from_iterable( map(lambda block: block.get_included_reward_coins(), blocks))) # excluded coin (not present in 'coins' and Merkle sets) excl_coin = coins.pop() for coin in reversed(coins): merkle_set_reverse.add_already_hashed(coin.name()) for coin in coins: merkle_set.add_already_hashed(coin.name()) for coin in coins: result, proof = merkle_set.is_included_already_hashed(coin.name()) assert result is True result_excl, proof_excl = merkle_set.is_included_already_hashed( excl_coin.name()) assert result_excl is False validate_proof = confirm_included_already_hashed( merkle_set.get_root(), coin.name(), proof) validate_proof_excl = confirm_included_already_hashed( merkle_set.get_root(), excl_coin.name(), proof_excl) assert validate_proof is True assert validate_proof_excl is False # Test if the order of adding items changes the outcome assert merkle_set.get_root() == merkle_set_reverse.get_root()
def validate_removals(self, coins, proofs, root): if proofs is None: # If there are no proofs, it means all removals were returned in the response. # we must find the ones relevant to our wallets. # Verify removals root removals_merkle_set = MerkleSet() for name_coin in coins: # TODO review all verification name, coin = name_coin if coin is not None: removals_merkle_set.add_already_hashed(coin.name()) removals_root = removals_merkle_set.get_root() if root != removals_root: return False else: # This means the full node has responded only with the relevant removals # for our wallet. Each merkle proof must be verified. if len(coins) != len(proofs): return False for i in range(len(coins)): # Coins are in the same order as proofs if coins[i][0] != proofs[i][0]: return False coin = coins[i][1] if coin is None: # Verifies merkle proof of exclusion not_included = confirm_not_included_already_hashed( root, coins[i][0], proofs[i][1], ) if not_included is False: return False else: # Verifies merkle proof of inclusion of coin name if coins[i][0] != coin.name(): return False included = confirm_included_already_hashed( root, coin.name(), proofs[i][1], ) if included is False: return False return True
def validate_additions( self, coins: List[Tuple[bytes32, List[Coin]]], proofs: Optional[List[Tuple[bytes32, bytes, Optional[bytes]]]], root, ): if proofs is None: # Verify root additions_merkle_set = MerkleSet() # Addition Merkle set contains puzzlehash and hash of all coins with that puzzlehash for puzzle_hash, coins_l in coins: additions_merkle_set.add_already_hashed(puzzle_hash) additions_merkle_set.add_already_hashed( hash_coin_list(coins_l)) additions_root = additions_merkle_set.get_root() if root != additions_root: return False else: for i in range(len(coins)): assert coins[i][0] == proofs[i][0] coin_list_1: List[Coin] = coins[i][1] # TODO: address hint error and remove ignore # error: Incompatible types in assignment (expression has type "bytes", variable has type # "bytes32") [assignment] puzzle_hash_proof: bytes32 = proofs[i][ 1] # type: ignore[assignment] # TODO: address hint error and remove ignore # error: Incompatible types in assignment (expression has type "Optional[bytes]", variable has # type "Optional[bytes32]") [assignment] coin_list_proof: Optional[bytes32] = proofs[i][ 2] # type: ignore[assignment] if len(coin_list_1) == 0: # Verify exclusion proof for puzzle hash not_included = confirm_not_included_already_hashed( root, coins[i][0], puzzle_hash_proof, ) if not_included is False: return False else: try: # Verify inclusion proof for coin list # TODO: address hint error and remove ignore # error: Argument 3 to "confirm_included_already_hashed" has incompatible type # "Optional[bytes32]"; expected "bytes32" [arg-type] included = confirm_included_already_hashed( root, hash_coin_list(coin_list_1), coin_list_proof, # type: ignore[arg-type] ) if included is False: return False except AssertionError: return False try: # Verify inclusion proof for puzzle hash included = confirm_included_already_hashed( root, coins[i][0], puzzle_hash_proof, ) if included is False: return False except AssertionError: return False return True