Skip to content

Commit

Permalink
Add an end to end test for mempool bundle fill rate and the resulting…
Browse files Browse the repository at this point in the history
… block validation.
  • Loading branch information
AmineKhaldi committed Aug 21, 2024
1 parent 49a8aab commit f98698a
Showing 1 changed file with 81 additions and 0 deletions.
81 changes: 81 additions & 0 deletions chia/_tests/core/mempool/test_mempool_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import dataclasses
import logging
import random
from typing import Any, Awaitable, Callable, Collection, Dict, List, Optional, Set, Tuple

import pytest
Expand Down Expand Up @@ -32,6 +33,7 @@
from chia.types.blockchain_format.program import INFINITE_COST, Program
from chia.types.blockchain_format.serialized_program import SerializedProgram
from chia.types.blockchain_format.sized_bytes import bytes32
from chia.types.clvm_cost import CLVMCost
from chia.types.coin_record import CoinRecord
from chia.types.coin_spend import CoinSpend, make_spend
from chia.types.condition_opcodes import ConditionOpcode
Expand Down Expand Up @@ -1937,3 +1939,82 @@ async def get_coin_records(coin_ids: Collection[bytes32]) -> List[CoinRecord]:
assert result[1] != MempoolInclusionStatus.FAILED
except ValidationError as e:
assert e.code == expected


@pytest.mark.anyio
@pytest.mark.anyio
async def test_fill_rate_block_validation(
simulator_and_wallet: OldSimulatorsAndWallets, seeded_random: random.Random
) -> None:
"""
This test creates puzzles of varying sizes and generates blocks with
various combinations of them, ensuring they pass block validation.
"""

async def send_to_mempool(full_node: FullNodeSimulator, spend_bundle: SpendBundle) -> None:
res = await full_node.send_transaction(wallet_protocol.SendTransaction(spend_bundle))
assert res is not None and ProtocolMessageTypes(res.type) == ProtocolMessageTypes.transaction_ack
res_parsed = wallet_protocol.TransactionAck.from_bytes(res.data)
assert res_parsed.status == MempoolInclusionStatus.SUCCESS.value

async def fill_mempool_with_test_sbs(full_node_api: FullNodeSimulator) -> None:
# Create puzzles of varying sizes and farm coins for them
conditions_pool = [
ConditionOpcode.RESERVE_FEE,
ConditionOpcode.CREATE_COIN,
ConditionOpcode.ASSERT_HEIGHT_ABSOLUTE,
ConditionOpcode.ASSERT_SECONDS_ABSOLUTE,
ConditionOpcode.CREATE_COIN_ANNOUNCEMENT,
ConditionOpcode.REMARK,
]
puzzles_and_coins = []
conditions = []
for i in range(15):
random_conditions_count = seeded_random.randint(1, len(conditions_pool))
opcodes = seeded_random.sample(conditions_pool, random_conditions_count)
for opcode in opcodes:
if opcode == ConditionOpcode.RESERVE_FEE:
conditions.append([opcode, uint64(i)])
elif opcode == ConditionOpcode.CREATE_COIN:
conditions.append([opcode, IDENTITY_PUZZLE_HASH, uint64(i)])
elif opcode == ConditionOpcode.ASSERT_HEIGHT_ABSOLUTE:
conditions.append([opcode, uint32(i)])
elif opcode == ConditionOpcode.ASSERT_SECONDS_ABSOLUTE:
conditions.append([opcode, uint64(i)])
elif opcode == ConditionOpcode.CREATE_COIN_ANNOUNCEMENT:
conditions.append([opcode, i.to_bytes(32, "big")])
elif opcode == ConditionOpcode.REMARK:
conditions.append([opcode, i])
# These puzzles are of the form (q . conditions)
puzzle = SerializedProgram.to((1, conditions))
ph = puzzle.get_tree_hash()
for _ in range(2):
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
coin_records = await full_node_api.full_node.coin_store.get_coin_records_by_puzzle_hash(False, ph)
puzzles_and_coins.append((puzzle, ph, coin_records[0].coin))
# Use the farmed coins to fill the mempool with bundles that spend them
for puzzle, ph, coin in puzzles_and_coins:
coin_spend = make_spend(coin, puzzle, SerializedProgram.to([]))
sb = SpendBundle([coin_spend], G2Element())
await send_to_mempool(full_node_api, sb)

[[full_node_api], _, _] = simulator_and_wallet
TEST_MAX_BLOCK_CLVM_COST = uint64(150_000_000)
assert full_node_api.full_node._mempool_manager is not None
full_node_api.full_node._mempool_manager.mempool.mempool_info = dataclasses.replace(
full_node_api.full_node._mempool_manager.mempool.mempool_info,
max_block_clvm_cost=CLVMCost(TEST_MAX_BLOCK_CLVM_COST),
)
full_node_api.full_node.blockchain.constants = full_node_api.full_node.blockchain.constants.replace(
MAX_BLOCK_COST_CLVM=TEST_MAX_BLOCK_CLVM_COST
)
# Generate blocks with various combinations of puzzles
for _ in range(10):
await fill_mempool_with_test_sbs(full_node_api)
# Farm the block to make sure we're passing block validation
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(IDENTITY_PUZZLE_HASH))
# Check that our resulting block is not empty
peak = full_node_api.full_node.blockchain.get_peak()
assert peak is not None
assert peak.is_transaction_block
assert peak.fees > 0

0 comments on commit f98698a

Please sign in to comment.