Skip to content

Commit 92cd6ee

Browse files
matt-o-howarvidn
andauthored
Add increment to skipped_items if we hit an Exception in mempool (#19286)
* add skip to exception * fix test as last coin gets skipped * Add skip to exception update (#19339) * don't throw exception when skipping FF or Dedup coin in mempool * skipping a dedup because of different solution is not an error * correct logging and tests * unit test skipping FF after 3 errors --------- Co-authored-by: Arvid Norberg <[email protected]>
1 parent 3a1f70a commit 92cd6ee

File tree

4 files changed

+57
-9
lines changed

4 files changed

+57
-9
lines changed

chia/_tests/core/mempool/test_mempool.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import pytest
99
from chia_rs import (
10+
ELIGIBLE_FOR_FF,
1011
ENABLE_KECCAK,
1112
ENABLE_KECCAK_OPS_OUTSIDE_GUARD,
1213
AugSchemeMPL,
@@ -2931,6 +2932,39 @@ def test_items_by_feerate(items: list[MempoolItem], expected: list[Coin]) -> Non
29312932
last_fpc = mi.fee_per_cost
29322933

29332934

2935+
# make sure that after failing to pick 3 fast-forward spends, we skip
2936+
# FF spends
2937+
@pytest.mark.anyio
2938+
async def test_skip_error_items() -> None:
2939+
fee_estimator = create_bitcoin_fee_estimator(uint64(11000000000))
2940+
mempool_info = MempoolInfo(
2941+
CLVMCost(uint64(11000000000 * 3)),
2942+
FeeRate(uint64(1000000)),
2943+
CLVMCost(uint64(11000000000)),
2944+
)
2945+
mempool = Mempool(mempool_info, fee_estimator)
2946+
2947+
# all 50 items support fast forward
2948+
for i in range(50):
2949+
item = mk_item(coins[i : i + 1], flags=[ELIGIBLE_FOR_FF], fee=0, cost=50)
2950+
add_info = mempool.add_to_pool(item)
2951+
assert add_info.error is None
2952+
2953+
called = 0
2954+
2955+
async def local_get_unspent_lineage_info(ph: bytes32) -> Optional[UnspentLineageInfo]:
2956+
nonlocal called
2957+
called += 1
2958+
raise RuntimeError("failed to find fast forward coin")
2959+
2960+
result = await mempool.create_block_generator(local_get_unspent_lineage_info, DEFAULT_CONSTANTS, uint32(10))
2961+
assert result is not None
2962+
generator, _, _ = result
2963+
2964+
assert called == 3
2965+
assert generator.program == SerializedProgram.from_bytes(bytes.fromhex("ff01ff8080"))
2966+
2967+
29342968
def rand_hash() -> bytes32:
29352969
rng = random.Random()
29362970
ret = bytearray(32)

chia/_tests/core/mempool/test_mempool_manager.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
DedupCoinSpend,
5353
EligibilityAndAdditions,
5454
EligibleCoinSpends,
55+
SkipDedup,
5556
UnspentLineageInfo,
5657
run_for_cost,
5758
)
@@ -1185,10 +1186,7 @@ async def make_and_send_big_cost_sb(coin: Coin) -> None:
11851186
assert result is not None
11861187
agg, additions = result
11871188
skipped_due_to_eligible_coins = sum(
1188-
1
1189-
for line in caplog.text.split("\n")
1190-
if "Exception while checking a mempool item for deduplication: Skipping transaction with eligible coin(s)"
1191-
in line
1189+
1 for line in caplog.text.split("\n") if "Skipping transaction with dedup or FF spends" in line
11921190
)
11931191
if num_skipped_items == PRIORITY_TX_THRESHOLD:
11941192
# We skipped enough big cost items to reach `PRIORITY_TX_THRESHOLD`,
@@ -1511,7 +1509,7 @@ def test_dedup_info_eligible_but_different_solution() -> None:
15111509
conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, TEST_COIN_AMOUNT]]
15121510
sb = spend_bundle_from_conditions(conditions, TEST_COIN)
15131511
mempool_item = mempool_item_from_spendbundle(sb)
1514-
with pytest.raises(ValueError, match="Solution is different from what we're deduplicating on"):
1512+
with pytest.raises(SkipDedup, match="Solution is different from what we're deduplicating on"):
15151513
eligible_coin_spends.get_deduplication_info(
15161514
bundle_coin_spends=mempool_item.bundle_coin_spends, max_cost=mempool_item.conds.cost
15171515
)

chia/full_node/mempool.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from chia.types.blockchain_format.serialized_program import SerializedProgram
2020
from chia.types.clvm_cost import CLVMCost
2121
from chia.types.coin_spend import CoinSpend
22-
from chia.types.eligible_coin_spends import EligibleCoinSpends, UnspentLineageInfo
22+
from chia.types.eligible_coin_spends import EligibleCoinSpends, SkipDedup, UnspentLineageInfo
2323
from chia.types.generator_types import BlockGenerator
2424
from chia.types.internal_mempool_item import InternalMempoolItem
2525
from chia.types.mempool_item import MempoolItem
@@ -558,11 +558,18 @@ async def create_bundle_from_mempool_items(
558558
# we want to keep looking for smaller transactions that
559559
# might fit, but we also want to avoid spending too much
560560
# time on potentially expensive ones, hence this shortcut.
561+
if any(
562+
map(
563+
lambda spend_data: (spend_data.eligible_for_dedup or spend_data.eligible_for_fast_forward),
564+
item.bundle_coin_spends.values(),
565+
)
566+
):
567+
log.info("Skipping transaction with dedup or FF spends {item.name}")
568+
continue
569+
561570
unique_coin_spends = []
562571
unique_additions = []
563572
for spend_data in item.bundle_coin_spends.values():
564-
if spend_data.eligible_for_dedup or spend_data.eligible_for_fast_forward:
565-
raise Exception(f"Skipping transaction with eligible coin(s): {name.hex()}")
566573
unique_coin_spends.append(spend_data.coin_spend)
567574
unique_additions.extend(spend_data.additions)
568575
cost_saving = 0
@@ -610,8 +617,12 @@ async def create_bundle_from_mempool_items(
610617
# find transactions small enough to fit at this point
611618
if self.mempool_info.max_block_clvm_cost - cost_sum < MIN_COST_THRESHOLD:
612619
break
620+
except SkipDedup as e:
621+
log.info(f"{e}")
622+
continue
613623
except Exception as e:
614624
log.info(f"Exception while checking a mempool item for deduplication: {e}")
625+
skipped_items += 1
615626
continue
616627
if processed_spend_bundles == 0:
617628
return None

chia/types/eligible_coin_spends.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@ def perform_the_fast_forward(
143143
return new_coin_spend, patched_additions
144144

145145

146+
@dataclasses.dataclass
147+
class SkipDedup(BaseException):
148+
msg: str
149+
150+
146151
@dataclasses.dataclass(frozen=True)
147152
class EligibleCoinSpends:
148153
deduplication_spends: dict[bytes32, DedupCoinSpend] = dataclasses.field(default_factory=dict)
@@ -200,7 +205,7 @@ def get_deduplication_info(
200205
# even if they end up saving more cost, as we're going for the first
201206
# solution we see from the relatively highest FPC item, to avoid
202207
# severe performance and/or time-complexity impact
203-
raise ValueError("Solution is different from what we're deduplicating on")
208+
raise SkipDedup("Solution is different from what we're deduplicating on")
204209
# Let's calculate the saved cost if we never did that before
205210
if duplicate_cost is None:
206211
# See first if this mempool item had this cost computed before

0 commit comments

Comments
 (0)