Skip to content
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
58 changes: 58 additions & 0 deletions chia/_tests/core/mempool/test_mempool_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -3201,3 +3201,61 @@ async def test_new_peak_deferred_ff_items() -> None:
latest_singleton_lineage2 = mi2.bundle_coin_spends[singleton2_id].latest_singleton_lineage
assert latest_singleton_lineage2 is not None
assert latest_singleton_lineage2.coin_id == singleton2_new_latest.name()


@pytest.mark.anyio
async def test_different_ff_versions() -> None:
"""
Covers the case where we send an item with an older ff singleton version
while the mempool is aware of a newer lineage.
"""
launcher_id = bytes32([1] * 32)
singleton_spend1 = make_singleton_spend(launcher_id, bytes32([2] * 32))
version1_id = singleton_spend1.coin.name()
singleton_spend2 = make_singleton_spend(launcher_id, bytes32([3] * 32))
version2_id = singleton_spend2.coin.name()
singleton_ph = singleton_spend2.coin.puzzle_hash
coins = TestCoins(
[singleton_spend1.coin, singleton_spend2.coin, TEST_COIN, TEST_COIN2], {singleton_ph: singleton_spend2.coin}
)
mempool_manager = await setup_mempool(coins)
mempool_items: list[MempoolItem] = []
for singleton_spend, regular_coin in [(singleton_spend1, TEST_COIN), (singleton_spend2, TEST_COIN2)]:
sb = SpendBundle([singleton_spend, mk_coin_spend(regular_coin)], G2Element())
sb_name = sb.name()
await mempool_manager.add_spend_bundle(
sb,
make_test_conds(spend_ids=[(singleton_spend.coin, ELIGIBLE_FOR_FF), (regular_coin, 0)], cost=1337),
sb_name,
uint32(1),
)
mi = mempool_manager.get_mempool_item(sb_name)
assert mi is not None
mempool_items.append(mi)
[mi1, mi2] = mempool_items
latest_lineage_id = version2_id
assert latest_lineage_id != version1_id
# Bundle coin spends key points to version 1 but the lineage is latest (v2)
latest_singleton_lineage1 = mi1.bundle_coin_spends[version1_id].latest_singleton_lineage
assert latest_singleton_lineage1 is not None
assert latest_singleton_lineage1.coin_id == latest_lineage_id
# Both the bundle coin spends key and the lineage point to latest (v2)
latest_singleton_lineage2 = mi2.bundle_coin_spends[version2_id].latest_singleton_lineage
assert latest_singleton_lineage2 is not None
assert latest_singleton_lineage2.coin_id == latest_lineage_id
# Let's update the lineage with a new version of the singleton
new_latest_lineage = Coin(version2_id, singleton_ph, singleton_spend2.coin.amount)
new_latest_lineage_id = new_latest_lineage.name()
coins.update_lineage(singleton_ph, new_latest_lineage)
await advance_mempool(mempool_manager, [version1_id, version2_id], use_optimization=True)
# Both items should get updated with the latest lineage
new_mi1 = mempool_manager.get_mempool_item(mi1.spend_bundle_name)
assert new_mi1 is not None
latest_singleton_lineage1 = new_mi1.bundle_coin_spends[version1_id].latest_singleton_lineage
assert latest_singleton_lineage1 is not None
assert latest_singleton_lineage1.coin_id == new_latest_lineage_id
new_mi2 = mempool_manager.get_mempool_item(mi2.spend_bundle_name)
assert new_mi2 is not None
latest_singleton_lineage2 = new_mi2.bundle_coin_spends[version2_id].latest_singleton_lineage
assert latest_singleton_lineage2 is not None
assert latest_singleton_lineage2.coin_id == new_latest_lineage_id
17 changes: 16 additions & 1 deletion chia/full_node/mempool_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,22 @@ def check_removals(
for item in conflicting_items:
if item in conflicts:
continue
conflict_bcs = item.bundle_coin_spends[coin_id]
conflict_bcs = item.bundle_coin_spends.get(coin_id)
if conflict_bcs is None:
# Check if this is an item that spends an older ff singleton
# version with a latest version that matches our coin ID.
conflict_bcs = next(
(
bcs
for bcs in item.bundle_coin_spends.values()
if bcs.latest_singleton_lineage is not None and bcs.latest_singleton_lineage.coin_id == coin_id
),
None,
)
# We're not expected to get here but let's handle it gracefully
if conflict_bcs is None:
log.warning(f"Coin ID {coin_id} expected but not found in mempool item {item.name}")
return Err.INVALID_SPEND_BUNDLE, []
# if the spend we're adding to the mempool is not DEDUP nor FF, it's
# just a regular conflict
if not coin_bcs.eligible_for_fast_forward and not coin_bcs.eligible_for_dedup:
Expand Down
Loading