Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix DID resync #15675

Merged
merged 9 commits into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions chia/wallet/wallet_state_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -985,6 +985,10 @@ async def handle_did(
assert wallet.did_info.origin_coin is not None
if origin_coin.name() == wallet.did_info.origin_coin.name():
return WalletIdentifier.create(wallet)
if coin_state.spent_height is not None:
# The first coin we received for DID wallet is spent.
# This means the wallet is in a resync process, skip the coin
return None
did_wallet = await DIDWallet.create_new_did_wallet_from_coin_spend(
self,
self.main_wallet,
Expand Down
95 changes: 95 additions & 0 deletions tests/wallet/did_wallet/test_did.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from chia.rpc.wallet_rpc_api import WalletRpcApi
from chia.simulator.setup_nodes import SimulatorsAndWallets
from chia.simulator.simulator_protocol import FarmNewBlockProtocol
from chia.simulator.time_out_assert import time_out_assert, time_out_assert_not_none
from chia.types.blockchain_format.program import Program
from chia.types.blockchain_format.sized_bytes import bytes32
Expand All @@ -17,6 +18,7 @@
from chia.types.spend_bundle import SpendBundle
from chia.util.bech32m import decode_puzzle_hash, encode_puzzle_hash
from chia.util.condition_tools import conditions_dict_for_solution
from chia.util.config import load_config
from chia.util.ints import uint16, uint64
from chia.wallet.did_wallet.did_wallet import DIDWallet
from chia.wallet.singleton import create_singleton_puzzle
Expand Down Expand Up @@ -1223,3 +1225,96 @@ async def test_create_did_with_recovery_list(self, self_hostname, two_nodes_two_
# json.loads(all_node_0_wallets[1].data)["current_inner"]
# == json.loads(all_node_1_wallets[1].data)["current_inner"]
# )

@pytest.mark.parametrize(
"trusted",
[True, False],
)
@pytest.mark.asyncio
async def test_did_resync(self, self_hostname, two_wallet_nodes, trusted) -> None:
ytx1991 marked this conversation as resolved.
Show resolved Hide resolved
full_nodes, wallets, _ = two_wallet_nodes
full_node_api = full_nodes[0]
server_1 = full_node_api.full_node.server
xdustinface marked this conversation as resolved.
Show resolved Hide resolved
wallet_node, server_2 = wallets[0]
xdustinface marked this conversation as resolved.
Show resolved Hide resolved
wallet_node_2, server_3 = wallets[1]
xdustinface marked this conversation as resolved.
Show resolved Hide resolved
wallet = wallet_node.wallet_state_manager.main_wallet
xdustinface marked this conversation as resolved.
Show resolved Hide resolved
wallet2 = wallet_node_2.wallet_state_manager.main_wallet
xdustinface marked this conversation as resolved.
Show resolved Hide resolved
fee = uint64(0)
api_0 = WalletRpcApi(wallet_node)
xdustinface marked this conversation as resolved.
Show resolved Hide resolved
ph = await wallet.get_new_puzzlehash()
if trusted:
wallet_node.config["trusted_peers"] = {server_1.node_id.hex(): server_1.node_id.hex()}
wallet_node_2.config["trusted_peers"] = {server_1.node_id.hex(): server_1.node_id.hex()}
else:
wallet_node.config["trusted_peers"] = {}
wallet_node_2.config["trusted_peers"] = {}
await server_2.start_client(PeerInfo(self_hostname, uint16(server_1._port)), None)
await server_3.start_client(PeerInfo(self_hostname, uint16(server_1._port)), None)
await full_node_api.farm_blocks_to_wallet(1, wallet)

async with wallet_node.wallet_state_manager.lock:
did_wallet_1: DIDWallet = await DIDWallet.create_new_did_wallet(
wallet_node.wallet_state_manager,
wallet,
uint64(101),
[bytes(ph)],
uint64(1),
{"Twitter": "Test", "GitHub": "测试"},
fee=fee,
)
assert did_wallet_1.get_name() == "Profile 1"
spend_bundle_list = await wallet_node.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(
did_wallet_1.id()
)
spend_bundle = spend_bundle_list[0].spend_bundle
await time_out_assert_not_none(5, full_node_api.full_node.mempool_manager.get_spendbundle, spend_bundle.name())
await full_node_api.farm_blocks_to_wallet(1, wallet2)
await time_out_assert(15, did_wallet_1.get_confirmed_balance, 101)
await time_out_assert(15, did_wallet_1.get_unconfirmed_balance, 101)
# Transfer DID
new_puzhash = await wallet2.get_new_puzzlehash()
await did_wallet_1.transfer_did(new_puzhash, fee, True)
spend_bundle_list = await wallet_node.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(
did_wallet_1.id()
)
spend_bundle = spend_bundle_list[0].spend_bundle
await time_out_assert_not_none(5, full_node_api.full_node.mempool_manager.get_spendbundle, spend_bundle.name())
await full_node_api.farm_blocks_to_wallet(1, wallet2)
# Check if the DID wallet is created in the wallet2

await time_out_assert(30, get_wallet_num, 2, wallet_node_2.wallet_state_manager)
await time_out_assert(30, get_wallet_num, 1, wallet_node.wallet_state_manager)
wallet_node_2._close()
await wallet_node_2._await_closed()
# set flag to reset wallet sync data on start
await api_0.set_wallet_resync_on_startup({"enable": True})
fingerprint = wallet_node.logged_in_fingerprint
assert wallet_node._wallet_state_manager
# 2 reward coins
assert len(await wallet_node._wallet_state_manager.coin_store.get_all_unspent_coins()) == 2
before_txs = await wallet_node.wallet_state_manager.tx_store.get_transaction_count_for_wallet(1)
# Delete tx records
await wallet_node.wallet_state_manager.tx_store.rollback_to_block(0)
wallet_node._close()
await wallet_node._await_closed()
config = load_config(wallet_node.root_path, "config.yaml")
# check that flag was set in config file
assert config["wallet"]["reset_sync_for_fingerprint"] == fingerprint
new_config = wallet_node.config.copy()
new_config["reset_sync_for_fingerprint"] = config["wallet"]["reset_sync_for_fingerprint"]
new_config["database_path"] = "wallet/db/blockchain_wallet_v2_test_CHALLENGE_KEY.sqlite"
wallet_node_2.config = new_config
wallet_node_2.root_path = wallet_node.root_path
wallet_node_2.local_keychain = wallet_node.local_keychain
# use second node to start the same wallet, reusing config and db
await wallet_node_2._start_with_fingerprint(fingerprint)
assert wallet_node_2._wallet_state_manager
xdustinface marked this conversation as resolved.
Show resolved Hide resolved
await server_3.start_client(PeerInfo(self_hostname, uint16(server_1._port)), None)
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(bytes32(b"\00" * 32)))
await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_2, timeout=20)
await time_out_assert(30, get_wallet_num, 1, wallet_node_2.wallet_state_manager)
after_txs = await wallet_node_2.wallet_state_manager.tx_store.get_transaction_count_for_wallet(1)
# transactions should be the same
assert after_txs == before_txs
xdustinface marked this conversation as resolved.
Show resolved Hide resolved
# Check unspent coins
assert len(await wallet_node_2._wallet_state_manager.coin_store.get_all_unspent_coins()) == 2