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

Do not return unexpected coins from get_coin_state #17850

Merged
merged 6 commits into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
44 changes: 43 additions & 1 deletion chia/_tests/wallet/test_wallet_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import time
import types
from pathlib import Path
from typing import List, Optional
from typing import Any, List, Optional

import pytest

Expand All @@ -17,6 +17,7 @@
from chia.protocols.wallet_protocol import CoinState
from chia.server.outbound_message import Message, make_msg
from chia.simulator.block_tools import test_constants
from chia.types.blockchain_format.coin import Coin
from chia.types.blockchain_format.sized_bytes import bytes32
from chia.types.full_block import FullBlock
from chia.types.mempool_inclusion_status import MempoolInclusionStatus
Expand All @@ -28,6 +29,7 @@
from chia.util.keychain import Keychain, KeyData, generate_mnemonic
from chia.util.misc import to_batches
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
from chia.wallet.util.wallet_sync_utils import PeerRequestException
from chia.wallet.wallet_node import Balance, WalletNode


Expand Down Expand Up @@ -578,3 +580,43 @@ def check_wallet_cache_empty() -> bool:
# Disconnect from the peer to make sure their entry in the cache is also deleted
await simulator_and_wallet[1][0][0]._server.get_connections()[0].close(120)
await time_out_assert(5, check_wallet_cache_empty, True)


@pytest.mark.limit_consensus_modes(reason="consensus rules irrelevant")
@pytest.mark.anyio
async def test_wallet_node_bad_coin_state_ignore(
self_hostname: str, simulator_and_wallet: OldSimulatorsAndWallets, monkeypatch: pytest.MonkeyPatch
) -> None:
[full_node_api], [(wallet_node, wallet_server)], _ = simulator_and_wallet

await wallet_server.start_client(PeerInfo(self_hostname, full_node_api.server.get_port()), None)

@api_request()
async def register_interest_in_coin(
self: Self, request: wallet_protocol.RegisterForCoinUpdates, *, test: bool = False
) -> Optional[Message]:
return make_msg(
ProtocolMessageTypes.respond_to_coin_update,
wallet_protocol.RespondToCoinUpdates(
[], uint32(0), [CoinState(Coin(bytes32([0] * 32), bytes32([0] * 32), uint64(0)), uint32(0), uint32(0))]
),
)

async def validate_received_state_from_peer(*args: Any) -> bool:
# It's an interesting case here where we don't hit this unless something is broken
return True # pragma: no cover

assert full_node_api.full_node._server is not None
monkeypatch.setattr(
full_node_api.full_node._server.get_connections()[0].api,
"register_interest_in_coin",
types.MethodType(register_interest_in_coin, full_node_api.full_node._server.get_connections()[0].api),
)
monkeypatch.setattr(
wallet_node,
"validate_received_state_from_peer",
types.MethodType(validate_received_state_from_peer, wallet_node),
)

with pytest.raises(PeerRequestException):
await wallet_node.get_coin_state([], wallet_node.get_full_node_peer())
4 changes: 4 additions & 0 deletions chia/wallet/wallet_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -1634,6 +1634,10 @@ async def get_coin_state(
if not self.is_trusted(peer):
valid_list = []
for coin in coin_state.coin_states:
if coin.coin.name() not in coin_names:
await peer.close(9999)
self.log.warning(f"Peer {peer.peer_node_id} sent us an unrequested coin state. Banning.")
raise PeerRequestException(f"Peer sent us unrequested coin state {coin}")
valid = await self.validate_received_state_from_peer(
coin, peer, self.get_cache_for_peer(peer), fork_height
)
Expand Down
Loading