Skip to content

Commit 1af33c3

Browse files
committed
Make sure the fee and cost specified in a NewTransaction match the ones from validating its spend bundle.
1 parent d159689 commit 1af33c3

File tree

2 files changed

+36
-8
lines changed

2 files changed

+36
-8
lines changed

chia/_tests/core/full_node/test_full_node.py

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3362,18 +3362,21 @@ async def test_pending_tx_cache_retry_on_new_peak(
33623362
@pytest.mark.anyio
33633363
@pytest.mark.parametrize("mismatch_cost", [True, False])
33643364
@pytest.mark.parametrize("mismatch_fee", [True, False])
3365+
@pytest.mark.parametrize("tx_already_seen", [True, False])
33653366
async def test_ban_for_mismatched_tx_cost_fee(
33663367
setup_two_nodes_fixture: tuple[list[FullNodeSimulator], list[tuple[WalletNode, ChiaServer]], BlockTools],
33673368
self_hostname: str,
33683369
mismatch_cost: bool,
33693370
mismatch_fee: bool,
3371+
tx_already_seen: bool,
33703372
) -> None:
33713373
"""
33723374
Tests that a peer gets banned if it sends a `NewTransaction` message with a
33733375
cost and/or fee that doesn't match the transaction's validation cost/fee.
3374-
We setup two full nodes with the test transaction as already seen, and we
3375-
check its validation cost and fee against the ones specified in the
3376-
`NewTransaction` message.
3376+
We setup two full nodes, and with `tx_already_seen` we control whether the
3377+
first full node has this transaction already or it needs to request it.
3378+
In both cases we check the transaction's validation cost and fee against
3379+
the ones specified in the `NewTransaction` message.
33773380
"""
33783381
nodes, _, bt = setup_two_nodes_fixture
33793382
full_node_1, full_node_2 = nodes
@@ -3384,17 +3387,26 @@ async def test_ban_for_mismatched_tx_cost_fee(
33843387
ws_con_2 = next(iter(server_2.all_connections.values()))
33853388
wallet = WalletTool(test_constants)
33863389
wallet_ph = wallet.get_new_puzzlehash()
3390+
# If we're covering that the first full node has this transaction already
3391+
# we must add it accordingly, otherwise we'll add it to the second node so
3392+
# that the first node requests it, reacting to the NewTransaction message.
3393+
if tx_already_seen:
3394+
node = full_node_1.full_node
3395+
ws_con = ws_con_1
3396+
else:
3397+
node = full_node_2.full_node
3398+
ws_con = ws_con_2
33873399
blocks = bt.get_consecutive_blocks(
33883400
3, guarantee_transaction_block=True, farmer_reward_puzzle_hash=wallet_ph, pool_reward_puzzle_hash=wallet_ph
33893401
)
33903402
for block in blocks:
3391-
await full_node_1.full_node.add_block(block)
3403+
await node.add_block(block)
33923404
# Create a transaction and add it to the relevant full node's mempool
33933405
coin = blocks[-1].get_included_reward_coins()[0]
33943406
sb = wallet.generate_signed_transaction(uint64(42), wallet_ph, coin)
33953407
sb_name = sb.name()
3396-
await full_node_1.full_node.add_transaction(sb, sb_name, ws_con_1)
3397-
mempool_item = full_node_1.full_node.mempool_manager.get_mempool_item(sb_name)
3408+
await node.add_transaction(sb, sb_name, ws_con)
3409+
mempool_item = node.mempool_manager.get_mempool_item(sb_name)
33983410
assert mempool_item is not None
33993411
# Now send a NewTransaction with a cost and/or fee mismatch from the second
34003412
# full node.
@@ -3407,6 +3419,14 @@ async def test_ban_for_mismatched_tx_cost_fee(
34073419
ws_con_1.peer_info = PeerInfo(full_node_2_ip, ws_con_1.peer_info.port)
34083420
# Send the NewTransaction message from the second node to the first
34093421
await ws_con_2.send_message(msg)
3422+
if not tx_already_seen:
3423+
# When the first full node receives the NewTransaction message and it
3424+
# hasen't seen the transaction before, it will issue a transaction
3425+
# request. We need to wait until it receives the transaction and add it
3426+
# to its mempool.
3427+
await time_out_assert(
3428+
10, lambda: full_node_1.full_node.mempool_manager.get_mempool_item(mempool_item.name) is not None
3429+
)
34103430
# Make sure the first full node has banned the second as the item it has
34113431
# already seen has a different validation cost and/or fee than the one from
34123432
# the NewTransaction message.

chia/full_node/full_node_api.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,16 @@ async def tx_request_and_timeout(full_node: FullNode, transaction_id: bytes32, t
226226
await random_peer.send_message(msg)
227227
await asyncio.sleep(5)
228228
counter += 1
229-
if full_node.mempool_manager.seen(transaction_id):
230-
break
229+
mempool_item = full_node.mempool_manager.get_mempool_item(transaction_id)
230+
if mempool_item is not None:
231+
if mempool_item.cost == transaction.cost and mempool_item.fee == transaction.fees:
232+
break
233+
self.log.warning(
234+
f"Banning peer {peer.peer_node_id}. Sent us a new tx {transaction_id} with mismatch "
235+
f"on cost {transaction.cost} vs validation cost {mempool_item.cost} and/or "
236+
f"fee {transaction.fees} vs {mempool_item.fee}."
237+
)
238+
await peer.close(RATE_LIMITER_BAN_SECONDS)
231239
except asyncio.CancelledError:
232240
pass
233241
finally:

0 commit comments

Comments
 (0)