Skip to content

Commit

Permalink
CHIA-1485 Simplify calling pre_validate_spendbundle and avoid spend v…
Browse files Browse the repository at this point in the history
…s spend bundle confusion (#18639)

Simplify calling pre_validate_spendbundle and avoid spend vs spend bundle confusion.
  • Loading branch information
AmineKhaldi authored Sep 30, 2024
1 parent 8552e35 commit 33e79e3
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 24 deletions.
24 changes: 12 additions & 12 deletions chia/_tests/core/mempool/test_mempool_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ async def test_empty_spend_bundle() -> None:
mempool_manager = await instantiate_mempool_manager(zero_calls_get_coin_records)
sb = SpendBundle([], G2Element())
with pytest.raises(ValidationError, match="INVALID_SPEND_BUNDLE"):
await mempool_manager.pre_validate_spendbundle(sb, sb.name())
await mempool_manager.pre_validate_spendbundle(sb)


@pytest.mark.anyio
Expand All @@ -467,7 +467,7 @@ async def test_negative_addition_amount() -> None:
conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, -1]]
sb = spend_bundle_from_conditions(conditions)
with pytest.raises(ValidationError, match="COIN_AMOUNT_NEGATIVE"):
await mempool_manager.pre_validate_spendbundle(sb, sb.name())
await mempool_manager.pre_validate_spendbundle(sb)


@pytest.mark.anyio
Expand All @@ -478,7 +478,7 @@ async def test_valid_addition_amount() -> None:
coin = Coin(IDENTITY_PUZZLE_HASH, IDENTITY_PUZZLE_HASH, max_amount)
sb = spend_bundle_from_conditions(conditions, coin)
# ensure this does not throw
_ = await mempool_manager.pre_validate_spendbundle(sb, sb.name())
_ = await mempool_manager.pre_validate_spendbundle(sb)


@pytest.mark.anyio
Expand All @@ -488,7 +488,7 @@ async def test_too_big_addition_amount() -> None:
conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, max_amount + 1]]
sb = spend_bundle_from_conditions(conditions)
with pytest.raises(ValidationError, match="COIN_AMOUNT_EXCEEDS_MAXIMUM"):
await mempool_manager.pre_validate_spendbundle(sb, sb.name())
await mempool_manager.pre_validate_spendbundle(sb)


@pytest.mark.anyio
Expand All @@ -500,7 +500,7 @@ async def test_duplicate_output() -> None:
]
sb = spend_bundle_from_conditions(conditions)
with pytest.raises(ValidationError, match="DUPLICATE_OUTPUT"):
await mempool_manager.pre_validate_spendbundle(sb, sb.name())
await mempool_manager.pre_validate_spendbundle(sb)


@pytest.mark.anyio
Expand All @@ -511,41 +511,41 @@ async def test_block_cost_exceeds_max() -> None:
conditions.append([ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, i])
sb = spend_bundle_from_conditions(conditions)
with pytest.raises(ValidationError, match="BLOCK_COST_EXCEEDS_MAX"):
await mempool_manager.pre_validate_spendbundle(sb, sb.name())
await mempool_manager.pre_validate_spendbundle(sb)


@pytest.mark.anyio
async def test_double_spend_prevalidation() -> None:
mempool_manager = await instantiate_mempool_manager(zero_calls_get_coin_records)
conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 1]]
sb = spend_bundle_from_conditions(conditions)
sb_twice: SpendBundle = SpendBundle.aggregate([sb, sb])
sb_twice = SpendBundle.aggregate([sb, sb])
with pytest.raises(ValidationError, match="DOUBLE_SPEND"):
await mempool_manager.pre_validate_spendbundle(sb_twice, sb_twice.name())
await mempool_manager.pre_validate_spendbundle(sb_twice)


@pytest.mark.anyio
async def test_minting_coin() -> None:
mempool_manager = await instantiate_mempool_manager(zero_calls_get_coin_records)
conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, TEST_COIN_AMOUNT]]
sb = spend_bundle_from_conditions(conditions)
_ = await mempool_manager.pre_validate_spendbundle(sb, sb.name())
_ = await mempool_manager.pre_validate_spendbundle(sb)
conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, TEST_COIN_AMOUNT + 1]]
sb = spend_bundle_from_conditions(conditions)
with pytest.raises(ValidationError, match="MINTING_COIN"):
await mempool_manager.pre_validate_spendbundle(sb, sb.name())
await mempool_manager.pre_validate_spendbundle(sb)


@pytest.mark.anyio
async def test_reserve_fee_condition() -> None:
mempool_manager = await instantiate_mempool_manager(zero_calls_get_coin_records)
conditions = [[ConditionOpcode.RESERVE_FEE, TEST_COIN_AMOUNT]]
sb = spend_bundle_from_conditions(conditions)
_ = await mempool_manager.pre_validate_spendbundle(sb, sb.name())
_ = await mempool_manager.pre_validate_spendbundle(sb)
conditions = [[ConditionOpcode.RESERVE_FEE, TEST_COIN_AMOUNT + 1]]
sb = spend_bundle_from_conditions(conditions)
with pytest.raises(ValidationError, match="RESERVE_FEE_CONDITION_FAILED"):
await mempool_manager.pre_validate_spendbundle(sb, sb.name())
await mempool_manager.pre_validate_spendbundle(sb)


@pytest.mark.anyio
Expand Down
14 changes: 7 additions & 7 deletions chia/full_node/mempool_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,17 +264,14 @@ def remove_seen(self, bundle_hash: bytes32) -> None:
self.seen_bundle_hashes.pop(bundle_hash)

async def pre_validate_spendbundle(
self,
new_spend: SpendBundle,
spend_name: bytes32,
bls_cache: Optional[BLSCache] = None,
self, spend_bundle: SpendBundle, spend_bundle_id: Optional[bytes32] = None, bls_cache: Optional[BLSCache] = None
) -> SpendBundleConditions:
"""
Errors are included within the cached_result.
This runs in another process so we don't block the main thread
"""

if new_spend.coin_spends == []:
if spend_bundle.coin_spends == []:
raise ValidationError(Err.INVALID_SPEND_BUNDLE, "Empty SpendBundle")

assert self.peak is not None
Expand All @@ -284,7 +281,7 @@ async def pre_validate_spendbundle(
sbc, new_cache_entries, duration = await asyncio.get_running_loop().run_in_executor(
self.pool,
validate_clvm_and_signature,
new_spend,
spend_bundle,
self.max_tx_clvm_cost,
self.constants,
self.peak.height,
Expand All @@ -305,10 +302,13 @@ async def pre_validate_spendbundle(

ret = NPCResult(None, sbc)

if spend_bundle_id is None:
spend_bundle_id = spend_bundle.name()

log.log(
logging.DEBUG if duration < 2 else logging.WARNING,
f"pre_validate_spendbundle took {duration:0.4f} seconds "
f"for {spend_name} (queue-size: {self._worker_queue_size})",
f"for {spend_bundle_id} (queue-size: {self._worker_queue_size})",
)
if ret.error is not None:
raise ValidationError(Err(ret.error), "pre_validate_spendbundle failed")
Expand Down
7 changes: 2 additions & 5 deletions chia/rpc/full_node_rpc_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -859,11 +859,8 @@ async def _validate_fee_estimate_cost(self, request: Dict[str, Any]) -> uint64:
raise ValueError(f"Request must contain exactly one of {ns}")

if "spend_bundle" in request:
spend_bundle: SpendBundle = SpendBundle.from_json_dict(request["spend_bundle"])
spend_name = spend_bundle.name()
conds: SpendBundleConditions = await self.service.mempool_manager.pre_validate_spendbundle(
spend_bundle, spend_name
)
spend_bundle = SpendBundle.from_json_dict(request["spend_bundle"])
conds: SpendBundleConditions = await self.service.mempool_manager.pre_validate_spendbundle(spend_bundle)
cost = conds.cost
elif "cost" in request:
cost = request["cost"]
Expand Down

0 comments on commit 33e79e3

Please sign in to comment.