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

checkpoint: into main from release/2.5.2 @ 6e542f051ef6ad2aca5f16c76c5c0e97a6616e29 #19285

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
2 changes: 1 addition & 1 deletion chia/_tests/core/mempool/test_mempool_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -1136,7 +1136,7 @@ async def make_and_send_big_cost_sb(coin: Coin) -> None:
skipped_due_to_eligible_coins = sum(
1
for line in caplog.text.split("\n")
if "DEBUG Exception while checking a mempool item for deduplication: Skipping transaction with eligible coin(s)"
if "Exception while checking a mempool item for deduplication: Skipping transaction with eligible coin(s)"
in line
)
if num_skipped_items == PRIORITY_TX_THRESHOLD:
Expand Down
44 changes: 43 additions & 1 deletion chia/_tests/core/mempool/test_singleton_fast_forward.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,47 @@ async def prepare_and_test_singleton(
return singleton, eve_coin_spend, inner_puzzle, remaining_coin


@pytest.mark.anyio
async def test_singleton_fast_forward_solo() -> None:
"""
We don't allow a spend bundle with *only* fast forward spends, since those
are difficult to evict from the mempool. They would always be valid as long as
the singleton exists.
"""
SINGLETON_AMOUNT = uint64(1337)
async with sim_and_client() as (sim, sim_client):
singleton, eve_coin_spend, inner_puzzle, _ = await prepare_and_test_singleton(
sim, sim_client, True, SINGLETON_AMOUNT, SINGLETON_AMOUNT
)
singleton_puzzle_hash = eve_coin_spend.coin.puzzle_hash
inner_puzzle_hash = inner_puzzle.get_tree_hash()
inner_conditions: list[list[Any]] = [
[ConditionOpcode.CREATE_COIN, inner_puzzle_hash, SINGLETON_AMOUNT],
]
singleton_coin_spend, _ = make_singleton_coin_spend(eve_coin_spend, singleton, inner_puzzle, inner_conditions)
# spending the eve coin is not eligible for fast forward, so we need to make this spend first, to test FF
await make_and_send_spend_bundle(sim, sim_client, [singleton_coin_spend], aggsig=G2Element())
unspent_lineage_info = await sim_client.service.coin_store.get_unspent_lineage_info_for_puzzle_hash(
singleton_puzzle_hash
)
singleton_child, _ = await get_singleton_and_remaining_coins(sim)
assert singleton_child.amount == SINGLETON_AMOUNT
assert unspent_lineage_info == UnspentLineageInfo(
coin_id=singleton_child.name(),
coin_amount=singleton_child.amount,
parent_id=eve_coin_spend.coin.name(),
parent_amount=singleton.amount,
parent_parent_id=eve_coin_spend.coin.parent_coin_info,
)

inner_conditions = [[ConditionOpcode.CREATE_COIN, inner_puzzle_hash, 21]]
# this is a FF spend that isn't combined with any other spend. It's not allowed
singleton_coin_spend, _ = make_singleton_coin_spend(eve_coin_spend, singleton, inner_puzzle, inner_conditions)
status, error = await sim_client.push_tx(SpendBundle([singleton_coin_spend], G2Element()))
assert error is Err.INVALID_SPEND_BUNDLE
assert status == MempoolInclusionStatus.FAILED


@pytest.mark.anyio
@pytest.mark.parametrize("is_eligible_for_ff", [True, False])
async def test_singleton_fast_forward_different_block(is_eligible_for_ff: bool) -> None:
Expand Down Expand Up @@ -544,7 +585,8 @@ async def test_singleton_fast_forward_same_block() -> None:
singleton_coin_spend, _ = make_singleton_coin_spend(
eve_coin_spend, singleton, inner_puzzle, inner_conditions
)
status, error = await sim_client.push_tx(SpendBundle([singleton_coin_spend], aggsig))
remaining_coin_spend = CoinSpend(remaining_coin, IDENTITY_PUZZLE, remaining_spend_solution)
status, error = await sim_client.push_tx(SpendBundle([singleton_coin_spend, remaining_coin_spend], aggsig))
assert error is None
assert status == MempoolInclusionStatus.SUCCESS

Expand Down
2 changes: 1 addition & 1 deletion chia/full_node/mempool.py
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,7 @@ async def create_bundle_from_mempool_items(
if self.mempool_info.max_block_clvm_cost - cost_sum < MIN_COST_THRESHOLD:
break
except Exception as e:
log.debug(f"Exception while checking a mempool item for deduplication: {e}")
log.info(f"Exception while checking a mempool item for deduplication: {e}")
continue
if processed_spend_bundles == 0:
return None
Expand Down
6 changes: 6 additions & 0 deletions chia/full_node/mempool_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,12 @@ async def validate_spend_bundle(
# If you reach here it's probably because your program reveal doesn't match the coin's puzzle hash
return Err.INVALID_SPEND_BUNDLE, None, []

# fast forward spends are only allowed when bundled with other, non-FF, spends
# in order to evict an FF spend, it must be associated with a normal
# spend that can be included in a block or invalidated some other way
if all([s.eligible_for_fast_forward for s in bundle_coin_spends.values()]):
return Err.INVALID_SPEND_BUNDLE, None, []

removal_record_dict: dict[bytes32, CoinRecord] = {}
removal_amount: int = 0
removal_records = await get_coin_records(removal_names)
Expand Down
Loading