示例#1
0
    async def test_subscribe_for_ph(self, wallet_node_simulator):
        num_blocks = 4
        full_nodes, wallets = wallet_node_simulator
        full_node_api = full_nodes[0]
        wallet_node, server_2 = wallets[0]
        fn_server = full_node_api.full_node.server
        wsm: WalletStateManager = wallet_node.wallet_state_manager

        await server_2.start_client(
            PeerInfo(self_hostname, uint16(fn_server._port)), None)
        incoming_queue, peer_id = await add_dummy_connection(
            fn_server, 12312, NodeType.WALLET)

        zero_ph = 32 * b"\0"
        junk_ph = 32 * b"\a"
        fake_wallet_peer = fn_server.all_connections[peer_id]
        msg = wallet_protocol.RegisterForPhUpdates([zero_ph], 0)
        msg_response = await full_node_api.register_interest_in_puzzle_hash(
            msg, fake_wallet_peer)

        assert msg_response.type == ProtocolMessageTypes.respond_to_ph_update.value
        data_response: RespondToPhUpdates = RespondToCoinUpdates.from_bytes(
            msg_response.data)
        assert data_response.coin_states == []

        # Farm few more with reward
        for i in range(0, num_blocks):
            if i == num_blocks - 1:
                await full_node_api.farm_new_transaction_block(
                    FarmNewBlockProtocol(zero_ph))
                await full_node_api.farm_new_transaction_block(
                    FarmNewBlockProtocol(junk_ph))
            else:
                await full_node_api.farm_new_transaction_block(
                    FarmNewBlockProtocol(zero_ph))

        msg = wallet_protocol.RegisterForPhUpdates([zero_ph], 0)
        msg_response = await full_node_api.register_interest_in_puzzle_hash(
            msg, fake_wallet_peer)
        assert msg_response.type == ProtocolMessageTypes.respond_to_ph_update.value
        data_response: RespondToPhUpdates = RespondToCoinUpdates.from_bytes(
            msg_response.data)
        assert len(data_response.coin_states
                   ) == 2 * num_blocks  # 2 per height farmer / pool reward

        # Farm more rewards to check the incoming queue for the updates
        for i in range(0, num_blocks):
            if i == num_blocks - 1:
                await full_node_api.farm_new_transaction_block(
                    FarmNewBlockProtocol(zero_ph))
                await full_node_api.farm_new_transaction_block(
                    FarmNewBlockProtocol(junk_ph))
            else:
                await full_node_api.farm_new_transaction_block(
                    FarmNewBlockProtocol(zero_ph))

        all_messages = await self.get_all_messages_in_queue(incoming_queue)

        zero_coin = await full_node_api.full_node.coin_store.get_coin_states_by_puzzle_hashes(
            True, [zero_ph])
        all_zero_coin = set(zero_coin)
        notified_zero_coins = set()

        for message in all_messages:
            if message.type == ProtocolMessageTypes.coin_state_update.value:
                data_response: CoinStateUpdate = CoinStateUpdate.from_bytes(
                    message.data)
                for coin_state in data_response.items:
                    notified_zero_coins.add(coin_state)
                assert len(data_response.items
                           ) == 2  # 2 per height farmer / pool reward

        assert all_zero_coin == notified_zero_coins

        # Test subscribing to more coins
        one_ph = 32 * b"\1"
        msg = wallet_protocol.RegisterForPhUpdates([one_ph], 0)
        msg_response = await full_node_api.register_interest_in_puzzle_hash(
            msg, fake_wallet_peer)
        peak = full_node_api.full_node.blockchain.get_peak()

        for i in range(0, num_blocks):
            if i == num_blocks - 1:
                await full_node_api.farm_new_transaction_block(
                    FarmNewBlockProtocol(zero_ph))
                await full_node_api.farm_new_transaction_block(
                    FarmNewBlockProtocol(junk_ph))
            else:
                await full_node_api.farm_new_transaction_block(
                    FarmNewBlockProtocol(zero_ph))

        for i in range(0, num_blocks):
            if i == num_blocks - 1:
                await full_node_api.farm_new_transaction_block(
                    FarmNewBlockProtocol(one_ph))
                await full_node_api.farm_new_transaction_block(
                    FarmNewBlockProtocol(junk_ph))
            else:
                await full_node_api.farm_new_transaction_block(
                    FarmNewBlockProtocol(one_ph))

        zero_coins = await full_node_api.full_node.coin_store.get_coin_states_by_puzzle_hashes(
            True, [zero_ph], peak.height + 1)
        one_coins = await full_node_api.full_node.coin_store.get_coin_states_by_puzzle_hashes(
            True, [one_ph])

        all_coins = set(zero_coins)
        all_coins.update(one_coins)

        all_messages = await self.get_all_messages_in_queue(incoming_queue)

        notified_all_coins = set()

        for message in all_messages:
            if message.type == ProtocolMessageTypes.coin_state_update.value:
                data_response: CoinStateUpdate = CoinStateUpdate.from_bytes(
                    message.data)
                for coin_state in data_response.items:
                    notified_all_coins.add(coin_state)
                assert len(data_response.items
                           ) == 2  # 2 per height farmer / pool reward

        assert all_coins == notified_all_coins

        wsm: WalletStateManager = wallet_node.wallet_state_manager
        wallet: Wallet = wsm.wallets[1]
        puzzle_hash = await wallet.get_new_puzzlehash()

        for i in range(0, num_blocks):
            if i == num_blocks - 1:
                await full_node_api.farm_new_transaction_block(
                    FarmNewBlockProtocol(puzzle_hash))
                await full_node_api.farm_new_transaction_block(
                    FarmNewBlockProtocol(junk_ph))
            else:
                await full_node_api.farm_new_transaction_block(
                    FarmNewBlockProtocol(puzzle_hash))

        funds = sum([
            calculate_pool_reward(uint32(i)) +
            calculate_base_farmer_reward(uint32(i))
            for i in range(1, num_blocks + 1)
        ])
        fn_amount = sum(cr.coin.amount
                        for cr in await full_node_api.full_node.coin_store.
                        get_coin_records_by_puzzle_hash(False, puzzle_hash))

        await time_out_assert(15, wallet.get_confirmed_balance, funds)
        assert funds == fn_amount

        msg_1 = wallet_protocol.RegisterForPhUpdates([puzzle_hash], 0)
        msg_response_1 = await full_node_api.register_interest_in_puzzle_hash(
            msg_1, fake_wallet_peer)
        assert msg_response_1.type == ProtocolMessageTypes.respond_to_ph_update.value
        data_response_1: RespondToPhUpdates = RespondToCoinUpdates.from_bytes(
            msg_response_1.data)
        assert len(data_response_1.coin_states
                   ) == 2 * num_blocks  # 2 per height farmer / pool reward

        tx_record = await wallet.generate_signed_transaction(
            uint64(10), puzzle_hash, uint64(0))
        assert len(tx_record.spend_bundle.removals()) == 1
        spent_coin = tx_record.spend_bundle.removals()[0]
        assert spent_coin.puzzle_hash == puzzle_hash

        await wallet.push_transaction(tx_record)

        await time_out_assert(15, tx_in_pool, True,
                              full_node_api.full_node.mempool_manager,
                              tx_record.spend_bundle.name())

        for i in range(0, num_blocks):
            await full_node_api.farm_new_transaction_block(
                FarmNewBlockProtocol(puzzle_hash))

        # Let's make sure the wallet can handle a non ephemeral launcher
        from chia.wallet.puzzles.singleton_top_layer import SINGLETON_LAUNCHER_HASH

        tx_record = await wallet.generate_signed_transaction(
            uint64(10), SINGLETON_LAUNCHER_HASH, uint64(0))
        await wallet.push_transaction(tx_record)

        await time_out_assert(15, tx_in_pool, True,
                              full_node_api.full_node.mempool_manager,
                              tx_record.spend_bundle.name())

        for i in range(0, num_blocks):
            await full_node_api.farm_new_transaction_block(
                FarmNewBlockProtocol(SINGLETON_LAUNCHER_HASH))

        # Send a transaction to make sure the wallet is still running
        tx_record = await wallet.generate_signed_transaction(
            uint64(10), junk_ph, uint64(0))
        await wallet.push_transaction(tx_record)

        await time_out_assert(15, tx_in_pool, True,
                              full_node_api.full_node.mempool_manager,
                              tx_record.spend_bundle.name())

        for i in range(0, num_blocks):
            await full_node_api.farm_new_transaction_block(
                FarmNewBlockProtocol(puzzle_hash))

        all_messages = await self.get_all_messages_in_queue(incoming_queue)

        notified_state = None

        for message in all_messages:
            if message.type == ProtocolMessageTypes.coin_state_update.value:
                data_response: CoinStateUpdate = CoinStateUpdate.from_bytes(
                    message.data)
                for coin_state in data_response.items:
                    if coin_state.coin.name() == spent_coin.name():
                        notified_state = coin_state

        assert notified_state is not None
        assert notified_state.coin == spent_coin
        assert notified_state.spent_height is not None
示例#2
0
    async def test_subscribe_for_ph_reorg(self, wallet_node_simulator):
        num_blocks = 4
        long_blocks = 20
        full_nodes, wallets = wallet_node_simulator
        full_node_api = full_nodes[0]
        wallet_node, server_2 = wallets[0]
        fn_server = full_node_api.full_node.server
        wsm: WalletStateManager = wallet_node.wallet_state_manager
        standard_wallet: Wallet = wsm.wallets[1]
        puzzle_hash = await standard_wallet.get_new_puzzlehash()

        await server_2.start_client(
            PeerInfo(self_hostname, uint16(fn_server._port)), None)
        incoming_queue, peer_id = await add_dummy_connection(
            fn_server, 12312, NodeType.WALLET)

        fake_wallet_peer = fn_server.all_connections[peer_id]
        zero_ph = 32 * b"\0"

        # Farm to create a coin that we'll track
        for i in range(0, num_blocks):
            await full_node_api.farm_new_transaction_block(
                FarmNewBlockProtocol(zero_ph))

        for i in range(0, long_blocks):
            await full_node_api.farm_new_transaction_block(
                FarmNewBlockProtocol(zero_ph))

        msg = wallet_protocol.RegisterForPhUpdates([puzzle_hash], 0)
        msg_response = await full_node_api.register_interest_in_puzzle_hash(
            msg, fake_wallet_peer)
        assert msg_response is not None
        await full_node_api.farm_new_transaction_block(
            FarmNewBlockProtocol(puzzle_hash))

        for i in range(0, num_blocks):
            await full_node_api.farm_new_transaction_block(
                FarmNewBlockProtocol(zero_ph))

        expected_height = uint32(long_blocks + 2 * num_blocks + 1)
        await time_out_assert(
            15, full_node_api.full_node.blockchain.get_peak_height,
            expected_height)

        coin_records = await full_node_api.full_node.coin_store.get_coin_records_by_puzzle_hash(
            True, puzzle_hash)
        assert len(coin_records) > 0
        fork_height = expected_height - num_blocks - 5
        req = ReorgProtocol(fork_height, expected_height + 5, zero_ph)
        await full_node_api.reorg_from_index_to_new_index(req)

        coin_records = await full_node_api.full_node.coin_store.get_coin_records_by_puzzle_hash(
            True, puzzle_hash)
        assert coin_records == []

        all_messages = await self.get_all_messages_in_queue(incoming_queue)

        coin_update_messages = []
        for message in all_messages:
            if message.type == ProtocolMessageTypes.coin_state_update.value:
                data_response: CoinStateUpdate = CoinStateUpdate.from_bytes(
                    message.data)
                coin_update_messages.append(data_response)

        # First state is creation, second one is a reorg
        assert len(coin_update_messages) == 2
        first = coin_update_messages[0]

        assert len(first.items) == 2
        first_state_coin_1 = first.items[0]
        assert first_state_coin_1.spent_height is None
        assert first_state_coin_1.created_height is not None
        first_state_coin_2 = first.items[1]
        assert first_state_coin_2.spent_height is None
        assert first_state_coin_2.created_height is not None

        second = coin_update_messages[1]
        assert second.fork_height == fork_height
        assert len(second.items) == 2
        second_state_coin_1 = second.items[0]
        assert second_state_coin_1.spent_height is None
        assert second_state_coin_1.created_height is None
        second_state_coin_2 = second.items[1]
        assert second_state_coin_2.spent_height is None
        assert second_state_coin_2.created_height is None
示例#3
0
    async def test_subscribe_for_hint_long_sync(self,
                                                wallet_two_node_simulator):
        num_blocks = 4
        full_nodes, wallets = wallet_two_node_simulator
        full_node_api = full_nodes[0]
        full_node_api_1 = full_nodes[1]

        wallet_node, server_2 = wallets[0]
        fn_server = full_node_api.full_node.server
        fn_server_1 = full_node_api_1.full_node.server

        wsm: WalletStateManager = wallet_node.wallet_state_manager

        await server_2.start_client(
            PeerInfo(self_hostname, uint16(fn_server._port)), None)
        incoming_queue, peer_id = await add_dummy_connection(
            fn_server, 12312, NodeType.WALLET)
        incoming_queue_1, peer_id_1 = await add_dummy_connection(
            fn_server_1, 12313, NodeType.WALLET)

        wt: WalletTool = bt.get_pool_wallet_tool()
        ph = wt.get_new_puzzlehash()
        for i in range(0, num_blocks):
            await full_node_api.farm_new_transaction_block(
                FarmNewBlockProtocol(ph))

        await asyncio.sleep(6)
        coins = await full_node_api.full_node.coin_store.get_coin_records_by_puzzle_hashes(
            False, [ph])
        coin_spent = coins[0].coin
        hint_puzzle_hash = 32 * b"\2"
        amount = 1
        amount_bin = int_to_bytes(1)
        hint = 32 * b"\5"

        fake_wallet_peer = fn_server.all_connections[peer_id]
        fake_wallet_peer_1 = fn_server_1.all_connections[peer_id_1]
        msg = wallet_protocol.RegisterForPhUpdates([hint], 0)
        msg_response = await full_node_api.register_interest_in_puzzle_hash(
            msg, fake_wallet_peer)
        msg_response_1 = await full_node_api_1.register_interest_in_puzzle_hash(
            msg, fake_wallet_peer_1)

        assert msg_response.type == ProtocolMessageTypes.respond_to_ph_update.value
        data_response: RespondToPhUpdates = RespondToCoinUpdates.from_bytes(
            msg_response.data)
        assert len(data_response.coin_states) == 0

        condition_dict = {
            ConditionOpcode.CREATE_COIN: [
                ConditionWithArgs(ConditionOpcode.CREATE_COIN,
                                  [hint_puzzle_hash, amount_bin, hint])
            ]
        }
        tx: SpendBundle = wt.generate_signed_transaction(
            10,
            wt.get_new_puzzlehash(),
            coin_spent,
            condition_dic=condition_dict,
        )
        await full_node_api.respond_transaction(RespondTransaction(tx),
                                                fake_wallet_peer)

        await time_out_assert(15, tx_in_pool,
                              True, full_node_api.full_node.mempool_manager,
                              tx.name())

        # Create more blocks than recent "short_sync_blocks_behind_threshold" so that node enters batch
        for i in range(0, 100):
            await full_node_api.farm_new_transaction_block(
                FarmNewBlockProtocol(ph))

        node1_height = full_node_api_1.full_node.blockchain.get_peak_height()
        assert node1_height is None

        await fn_server_1.start_client(
            PeerInfo(self_hostname, uint16(fn_server._port)), None)
        node0_height = full_node_api.full_node.blockchain.get_peak_height()
        await time_out_assert(
            15, full_node_api_1.full_node.blockchain.get_peak_height,
            node0_height)

        all_messages = await self.get_all_messages_in_queue(incoming_queue)
        all_messages_1 = await self.get_all_messages_in_queue(incoming_queue_1)

        def check_messages_for_hint(messages):
            notified_state = None

            for message in messages:
                if message.type == ProtocolMessageTypes.coin_state_update.value:
                    data_response: CoinStateUpdate = CoinStateUpdate.from_bytes(
                        message.data)
                    notified_state = data_response
                    break

            assert notified_state is not None
            assert notified_state.items[0].coin == Coin(
                coin_spent.name(), hint_puzzle_hash, amount)

        check_messages_for_hint(all_messages)
        check_messages_for_hint(all_messages_1)
    uint32(4130100992),
    uint32(17664086),
    [header_block],
)

coin_state = wallet_protocol.CoinState(
    coin_1,
    uint32(2287030048),
    uint32(3361305811),
)

register_for_ph_updates = wallet_protocol.RegisterForPhUpdates(
    [
        bytes32(
            bytes.fromhex(
                "df24b7dc1d5ffa12f112e198cd26385b5ab302b5c2e5f9d589e5cd3f7b900510"
            ))
    ],
    uint32(874269130),
)

respond_to_ph_updates = wallet_protocol.RespondToPhUpdates(
    [
        bytes32(
            bytes.fromhex(
                "1be3bdc54b84901554e4e843966cfa3be3380054c968bebc41cc6be4aa65322f"
            ))
    ],
    uint32(3664709982),
    [coin_state],
)