def test_proof_prefix_with_other_nodes(): node_trie = Trie(PersistentDB(KeyValueStorageInMemory())) client_trie = Trie(PersistentDB(KeyValueStorageInMemory())) prefix = 'abcdefgh' other_nodes_count = 1000 prefix_nodes_count = 100 # Some nodes before prefix node for _ in range(other_nodes_count): node_trie.update(randomString(randint(8, 19)).encode(), rlp_encode([randomString(15)])) keys_suffices = set() while len(keys_suffices) != prefix_nodes_count: keys_suffices.add(randint(25, 250000)) key_vals = {'{}{}'.format(prefix, k): str(randint(3000, 5000)) for k in keys_suffices} for k, v in key_vals.items(): node_trie.update(k.encode(), rlp_encode([v])) # Some nodes after prefix node for _ in range(other_nodes_count): node_trie.update(randomString(randint(8, 19)).encode(), rlp_encode([randomString(15)])) proof_nodes = node_trie.generate_state_proof_for_key_prfx(prefix.encode()) encoded = {k.encode(): rlp_encode([v]) for k, v in key_vals.items()} assert client_trie.verify_spv_proof_multi(node_trie.root_hash, encoded, proof_nodes) # Change value of one of any random key encoded_new = deepcopy(encoded) random_key = next(iter(encoded_new.keys())) encoded_new[random_key] = rlp_encode([rlp_decode(encoded_new[random_key])[0] + b'2212']) assert not client_trie.verify_spv_proof_multi(node_trie.root_hash, encoded_new, proof_nodes)
def test_get_fees_with_proof(helpers, fees_set, fees): """ Get the sovtokenfees from the ledger """ result = helpers.general.do_get_fees() fees = result[FEES] state_proof = result[STATE_PROOF] assert state_proof proof_nodes = decode_proof(result[STATE_PROOF][PROOF_NODES]) client_trie = Trie(PersistentDB(KeyValueStorageInMemory())) fees = rlp_encode([StaticFeesReqHandler.state_serializer.serialize(fees)]) assert client_trie.verify_spv_proof( state_roots_serializer.deserialize(result[STATE_PROOF][ROOT_HASH]), StaticFeesReqHandler.fees_state_key, fees, proof_nodes)
def test_state_proof(public_minting, looper, # noqa sdk_pool_handle, sdk_wallet_client, seller_token_wallet, seller_address, user1_token_wallet, user1_address): res = send_get_utxo(looper, seller_address, sdk_wallet_client, sdk_pool_handle) update_token_wallet_with_result(seller_token_wallet, res) # Do 20 XFER txns for _ in range(20): utxos = [_ for lst in seller_token_wallet.get_all_wallet_utxos().values() for _ in lst] seq_no, amount = utxos[0] inputs = [[seller_token_wallet, seller_address, seq_no]] outputs = [{"address": user1_address, "amount": 1}, {"address": seller_address, "amount": amount-1}] res = send_xfer(looper, inputs, outputs, sdk_pool_handle) update_token_wallet_with_result(seller_token_wallet, res) res = send_get_utxo(looper, seller_address, sdk_wallet_client, sdk_pool_handle) update_token_wallet_with_result(seller_token_wallet, res) res = send_get_utxo(looper, user1_address, sdk_wallet_client, sdk_pool_handle) update_token_wallet_with_result(user1_token_wallet, res) res = send_get_utxo(looper, user1_address, sdk_wallet_client, sdk_pool_handle) # Check presence of state proof assert res[STATE_PROOF] encoded = {} outputs = res[OUTPUTS] for out in outputs: state_key = TokenStaticHelper.create_state_key(out["address"], out["seqNo"]) encoded[state_key] = rlp_encode([str(out["amount"])]) proof_nodes = decode_proof(res[STATE_PROOF][PROOF_NODES]) client_trie = Trie(PersistentDB(KeyValueStorageInMemory())) assert client_trie.verify_spv_proof_multi( state_roots_serializer.deserialize(res[STATE_PROOF][ROOT_HASH]), encoded, proof_nodes)
def test_get_prefix_nodes(): trie = Trie(PersistentDB(KeyValueStorageInMemory())) prefix = 'abcd' prefix_nibbles = bin_to_nibbles(prefix) key1 = prefix + '1' key2 = prefix + '2' key3 = prefix + '3' trie.update(key1.encode(), rlp_encode(['v1'])) seen_prefix = [] last_node = trie._get_last_node_for_prfx(trie.root_node, prefix_nibbles, seen_prfx=seen_prefix) # The last node should be a leaf since only 1 key assert trie._get_node_type(last_node) == NODE_TYPE_LEAF # Seen prefix matches the prefix exactly assert seen_prefix == [] # The queried key is larger than prefix, results in blank node last_node_ = trie._get_last_node_for_prfx(trie.root_node, bin_to_nibbles(prefix + '5'), []) assert last_node_ == BLANK_NODE seen_prefix = [] trie.update(key2.encode(), rlp_encode(['v2'])) last_node = trie._get_last_node_for_prfx(trie.root_node, prefix_nibbles, seen_prfx=seen_prefix) # The last node should be an extension since more than 1 key assert trie._get_node_type(last_node) == NODE_TYPE_EXTENSION assert seen_prefix == [] seen_prefix = [] trie.update(key3.encode(), rlp_encode(['v3'])) last_node = trie._get_last_node_for_prfx(trie.root_node, prefix_nibbles, seen_prfx=seen_prefix) assert trie._get_node_type(last_node) == NODE_TYPE_EXTENSION assert seen_prefix == [] last_node_key = without_terminator(unpack_to_nibbles(last_node[0])) # Key for the fetched prefix nodes (ignore last nibble) is same as prefix nibbles assert last_node_key[:-1] == prefix_nibbles # The extension node is correctly decoded. decoded_extension = trie._decode_to_node(last_node[1]) assert decoded_extension[1] == [b' ', rlp_encode(['v1'])] assert decoded_extension[2] == [b' ', rlp_encode(['v2'])] assert decoded_extension[3] == [b' ', rlp_encode(['v3'])] # Add keys with extended prefix extended_prefix = '1' key4 = prefix + extended_prefix + '85' trie.update(key4.encode(), rlp_encode(['v11'])) key5 = prefix + extended_prefix + '96' trie.update(key5.encode(), rlp_encode(['v12'])) seen_prefix = [] new_prefix_nibbs = bin_to_nibbles(prefix + extended_prefix) last_node = trie._get_last_node_for_prfx(trie.root_node, new_prefix_nibbs, seen_prfx=seen_prefix) assert trie._get_node_type(last_node) == NODE_TYPE_BRANCH assert new_prefix_nibbs == seen_prefix assert seen_prefix == bin_to_nibbles(prefix + '1') # traverse to the next node remaining_key4_nibbs = bin_to_nibbles(key4)[len(seen_prefix):] remaining_key5_nibbs = bin_to_nibbles(key5)[len(seen_prefix):] next_nibble = remaining_key4_nibbs[0] if remaining_key4_nibbs[ 0] > remaining_key5_nibbs[0] else remaining_key5_nibbs[0] next_node = trie._decode_to_node(last_node[next_nibble]) assert trie._get_node_type(next_node) == NODE_TYPE_BRANCH # The 8th index should lead to a node with key '5', key4 ended in '85' assert trie._get_node_type(next_node[8]) == NODE_TYPE_LEAF assert without_terminator(unpack_to_nibbles( next_node[8][0])) == bin_to_nibbles('5') # The 9th index should lead to a node with key '6', key5 ended in '96' assert trie._get_node_type(next_node[9]) == NODE_TYPE_LEAF assert without_terminator(unpack_to_nibbles( next_node[9][0])) == bin_to_nibbles('6') prefix_1 = prefix + 'efgh' prefix_1_nibbles = bin_to_nibbles(prefix_1) key1 = prefix_1 + '1' key2 = prefix_1 + '2' key3 = prefix_1 + '3' trie.update(key1.encode(), rlp_encode(['v1'])) trie.update(key2.encode(), rlp_encode(['v1'])) trie.update(key3.encode(), rlp_encode(['v1'])) seen_prefix = [] last_node = trie._get_last_node_for_prfx(trie.root_node, prefix_1_nibbles, seen_prfx=seen_prefix) assert trie._get_node_type(last_node) == NODE_TYPE_EXTENSION assert len(seen_prefix) > 0 assert starts_with(prefix_1_nibbles, seen_prefix)
def test_get_proof_and_value_no_key(): node_trie = Trie(PersistentDB(KeyValueStorageInMemory())) assert ([], None) == node_trie.produce_spv_proof(b"unknown_key", get_value=True)
def test_proof_specific_root(): node_trie = Trie(PersistentDB(KeyValueStorageInMemory())) client_trie = Trie(PersistentDB(KeyValueStorageInMemory())) kvs = OrderedDict({ 'k1': 'v1', 'k2': 'v2', 'x3': 'v3', 'x4': 'v5', 'x5': 'v7', 'y99': 'v6' }) size = len(kvs) # Only add some keys old_keys = set() i = 0 for k, v in kvs.items(): node_trie.update(k.encode(), rlp_encode([v])) old_keys.add(k) i += 1 if i >= size // 2: break # Record the root root_hash_0 = node_trie.root_hash root_node_0 = deepcopy(node_trie.root_node) # Add remaining keys new_keys = set() i = 0 for k, v in reversed(kvs.items()): node_trie.update(k.encode(), rlp_encode([v])) new_keys.add(k) i += 1 if i >= size // 2: break # Record new roots root_hash_1 = node_trie.root_hash root_node_1 = deepcopy(node_trie.root_node) # Check each root present for k, v in kvs.items(): assert node_trie.get(k.encode()) == rlp_encode([v]) # Old and new roots should be different assert root_hash_0 != root_hash_1 assert root_node_0 != root_node_1 # Generate and verify proof for both old (if key was present) and new roots for k, v in kvs.items(): k, v = k.encode(), rlp_encode([v]) if k in old_keys: old_root_proof = node_trie.generate_state_proof(k, root=root_node_0) assert client_trie.verify_spv_proof(root_hash_0, k, v, old_root_proof) new_root_proof = node_trie.generate_state_proof(k, root=root_node_1) assert client_trie.verify_spv_proof(root_hash_1, k, v, new_root_proof)
def test_get_values_at_roots_in_memory(): # Update key with different values but preserve root after each update # Check values of keys with different previous roots and check that they # are correct trie = Trie(PersistentDB(KeyValueStorageInMemory())) trie.update('k1'.encode(), rlp_encode(['v1'])) # print state.root_hash.encode('hex') # print state.root_node val = trie.get('k1') print(rlp_decode(val)) oldroot1 = trie.root_node old_root1_hash = trie.root_hash assert trie._decode_to_node(old_root1_hash) == oldroot1 trie.update('k1'.encode(), rlp_encode(['v1a'])) val = trie.get('k1') assert rlp_decode(val) == [b'v1a', ] # Already saved roots help in getting previous values oldval = trie.get_at(oldroot1, 'k1') assert rlp_decode(oldval) == [b'v1', ] oldroot1a = trie.root_node trie.update('k1'.encode(), rlp_encode([b'v1b'])) val = trie.get('k1') assert rlp_decode(val) == [b'v1b'] oldval = trie.get_at(oldroot1a, 'k1') assert rlp_decode(oldval) == [b'v1a', ] oldval = trie.get_at(oldroot1, 'k1') assert rlp_decode(oldval) == [b'v1', ] oldroot1b = trie.root_node trie.update('k1'.encode(), rlp_encode([b'v1c'])) val = trie.get('k1') assert rlp_decode(val) == [b'v1c', ] oldval = trie.get_at(oldroot1b, 'k1') assert rlp_decode(oldval) == [b'v1b', ] oldval = trie.get_at(oldroot1a, 'k1') assert rlp_decode(oldval) == [b'v1a', ] oldval = trie.get_at(oldroot1, 'k1') assert rlp_decode(oldval) == [b'v1', ] oldroot1c = trie.root_node trie.delete('k1'.encode()) assert trie.get('k1') == BLANK_NODE oldval = trie.get_at(oldroot1c, 'k1') assert rlp_decode(oldval) == [b'v1c', ] oldval = trie.get_at(oldroot1b, 'k1') assert rlp_decode(oldval) == [b'v1b', ] oldval = trie.get_at(oldroot1a, 'k1') assert rlp_decode(oldval) == [b'v1a', ] oldval = trie.get_at(oldroot1, 'k1') assert rlp_decode(oldval) == [b'v1', ] trie.root_node = oldroot1c val = trie.get('k1') assert rlp_decode(val) == [b'v1c', ] trie.root_node = oldroot1 val = trie.get('k1') assert rlp_decode(val) == [b'v1', ]