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
4 changes: 2 additions & 2 deletions chia/_tests/core/mempool/test_singleton_fast_forward.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def test_process_fast_forward_spends_nothing_to_do() -> None:
original_version = dataclasses.replace(internal_mempool_item)
singleton_ff = SingletonFastForward()
bundle_coin_spends = singleton_ff.process_fast_forward_spends(
mempool_item=internal_mempool_item, height=TEST_HEIGHT, constants=DEFAULT_CONSTANTS
mempool_item=internal_mempool_item, prev_tx_height=TEST_HEIGHT, constants=DEFAULT_CONSTANTS
)
assert singleton_ff == SingletonFastForward()
assert bundle_coin_spends == original_version.bundle_coin_spends
Expand Down Expand Up @@ -91,7 +91,7 @@ def test_process_fast_forward_spends_latest_unspent() -> None:
original_version = dataclasses.replace(internal_mempool_item)
singleton_ff = SingletonFastForward()
bundle_coin_spends = singleton_ff.process_fast_forward_spends(
mempool_item=internal_mempool_item, height=TEST_HEIGHT, constants=DEFAULT_CONSTANTS
mempool_item=internal_mempool_item, prev_tx_height=TEST_HEIGHT, constants=DEFAULT_CONSTANTS
)
child_coin = item.bundle_coin_spends[test_coin.name()].additions[0]
expected_fast_forward_spends = {
Expand Down
2 changes: 2 additions & 0 deletions chia/_tests/util/get_name_puzzle_conditions.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ def get_name_puzzle_conditions(
height: uint32,
constants: ConsensusConstants,
) -> NPCResult:
# TODO: technically, this is supposed to be the previous transaction block
# height. But this is just for testing and it seems to be OK for now
flags = get_flags_for_height_and_constants(height, constants) | DONT_VALIDATE_SIGNATURE

if mempool_mode:
Expand Down
4 changes: 2 additions & 2 deletions chia/_tests/wallet/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,11 @@ async def new_create(*args: Any, **kwargs: Any) -> Any:
return new_create

def run_block(
block: FullBlock, prev_generators: list[bytes], constants: ConsensusConstants
block: FullBlock, prev_generators: list[bytes], prev_tx_height: uint32, constants: ConsensusConstants
) -> tuple[Optional[int], Optional[SpendBundleConditions]]:
assert block.transactions_generator is not None
assert block.transactions_info is not None
flags = get_flags_for_height_and_constants(block.height, constants) | DONT_VALIDATE_SIGNATURE
flags = get_flags_for_height_and_constants(prev_tx_height, constants) | DONT_VALIDATE_SIGNATURE
if block.height >= constants.HARD_FORK_HEIGHT:
run_block = run_block_generator2
else:
Expand Down
9 changes: 8 additions & 1 deletion chia/consensus/blockchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,14 @@ async def run_single_block(self, block: FullBlock, fork_info: ForkInfo) -> None:
assert block_generator is not None
assert block.transactions_info is not None
assert block.foliage_transaction_block is not None
flags = get_flags_for_height_and_constants(block.height, self.constants)
prev_tx_height = pre_sp_tx_block_height(
constants=self.constants,
blocks=self,
prev_b_hash=block.prev_header_hash,
sp_index=block.reward_chain_block.signage_point_index,
first_in_sub_slot=len(block.finished_sub_slots) > 0,
)
flags = get_flags_for_height_and_constants(prev_tx_height, self.constants)
additions, removals = additions_and_removals(
bytes(block.transactions_generator),
block_generator.generator_refs,
Expand Down
13 changes: 10 additions & 3 deletions chia/consensus/multiprocess_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,11 @@ def validated_signature(self) -> bool:

# this layer of abstraction is here to let wallet tests monkeypatch it
def _run_block(
block: FullBlock, prev_generators: list[bytes], constants: ConsensusConstants
block: FullBlock, prev_generators: list[bytes], prev_tx_height: uint32, constants: ConsensusConstants
) -> tuple[Optional[int], Optional[SpendBundleConditions]]:
assert block.transactions_generator is not None
assert block.transactions_info is not None
flags = get_flags_for_height_and_constants(block.height, constants)
flags = get_flags_for_height_and_constants(prev_tx_height, constants)
if block.height >= constants.HARD_FORK_HEIGHT:
run_block = run_block_generator2
else:
Expand Down Expand Up @@ -116,7 +116,14 @@ def _pre_validate_block(
uint16(Err.BLOCK_COST_EXCEEDS_MAX.value), None, None, uint32(validation_time * 1000)
)

err, conds = _run_block(block, prev_generators, constants)
prev_tx_height = pre_sp_tx_block_height(
constants=constants,
blocks=blockchain,
prev_b_hash=block.prev_header_hash,
sp_index=block.reward_chain_block.signage_point_index,
first_in_sub_slot=len(block.finished_sub_slots) > 0,
)
err, conds = _run_block(block, prev_generators, prev_tx_height, constants)

assert (err is None) != (conds is None)
if err is not None:
Expand Down
6 changes: 3 additions & 3 deletions chia/full_node/eligible_coin_spends.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ class SingletonFastForward:
fast_forward_spends: dict[bytes32, UnspentLineageInfo] = dataclasses.field(default_factory=dict)

def process_fast_forward_spends(
self, *, mempool_item: InternalMempoolItem, height: uint32, constants: ConsensusConstants
self, *, mempool_item: InternalMempoolItem, prev_tx_height: uint32, constants: ConsensusConstants
) -> dict[bytes32, BundleCoinSpend]:
"""
Provides the caller with a `bundle_coin_spends` map that has a proper
Expand All @@ -182,7 +182,7 @@ def process_fast_forward_spends(
Args:
mempool_item: The internal mempool item to process
constants: needed in order to refresh the mempool item if needed
height: needed in order to refresh the mempool item if needed
prev_tx_height: needed in order to refresh the mempool item if needed

Returns:
The resulting `bundle_coin_spends` map of coin IDs to coin spends
Expand Down Expand Up @@ -273,7 +273,7 @@ def process_fast_forward_spends(
try:
# Run the new spend bundle to make sure it remains valid. What we
# care about here is whether this call throws or not.
get_conditions_from_spendbundle(new_sb, mempool_item.conds.cost, constants, height)
get_conditions_from_spendbundle(new_sb, mempool_item.conds.cost, constants, prev_tx_height)
# get_conditions_from_spendbundle raises a ValueError with an error code
except ValueError as e:
# Convert that to a ValidationError
Expand Down
10 changes: 9 additions & 1 deletion chia/full_node/full_node_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
from chia.consensus.block_creation import create_unfinished_block
from chia.consensus.blockchain import BlockchainMutexPriority
from chia.consensus.generator_tools import get_block_header
from chia.consensus.get_block_challenge import pre_sp_tx_block_height
from chia.consensus.get_block_generator import get_block_generator
from chia.consensus.pot_iterations import calculate_ip_iters, calculate_iterations_quality, calculate_sp_iters
from chia.consensus.signage_point import SignagePoint
Expand Down Expand Up @@ -1274,7 +1275,14 @@ async def request_block_header(self, request: wallet_protocol.RequestBlockHeader
# transactions_generator, so the block_generator should always be set
assert block_generator is not None, "failed to get block_generator for tx-block"

flags = get_flags_for_height_and_constants(request.height, self.full_node.constants)
prev_tx_height = pre_sp_tx_block_height(
constants=self.full_node.constants,
blocks=self.full_node.blockchain,
prev_b_hash=block.prev_header_hash,
sp_index=block.reward_chain_block.signage_point_index,
first_in_sub_slot=len(block.finished_sub_slots) > 0,
)
flags = get_flags_for_height_and_constants(prev_tx_height, self.full_node.constants)
additions, removals = await asyncio.get_running_loop().run_in_executor(
self.executor,
additions_and_removals,
Expand Down
28 changes: 25 additions & 3 deletions chia/full_node/full_node_rpc_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from chia_rs.sized_ints import uint32, uint64, uint128

from chia.consensus.blockchain import Blockchain, BlockchainMutexPriority
from chia.consensus.get_block_challenge import pre_sp_tx_block_height
from chia.consensus.get_block_generator import get_block_generator
from chia.consensus.pos_quality import UI_ACTUAL_SPACE_CONSTANT_FACTOR
from chia.full_node.fee_estimator_interface import FeeEstimatorInterface
Expand Down Expand Up @@ -489,7 +490,14 @@ async def get_block_spends(self, request: dict[str, Any]) -> EndpointResult:
if block_generator is None: # if block is not a transaction block.
return {"block_spends": []}

flags = get_flags_for_height_and_constants(full_block.height, self.service.constants)
prev_tx_height = pre_sp_tx_block_height(
constants=self.service.constants,
blocks=self.service.blockchain,
prev_b_hash=full_block.prev_header_hash,
sp_index=full_block.reward_chain_block.signage_point_index,
first_in_sub_slot=len(full_block.finished_sub_slots) > 0,
)
flags = get_flags_for_height_and_constants(prev_tx_height, self.service.constants)
spends = await asyncio.get_running_loop().run_in_executor(
self.executor,
get_spends_for_trusted_block,
Expand All @@ -513,7 +521,14 @@ async def get_block_spends_with_conditions(self, request: dict[str, Any]) -> End
if block_generator is None: # if block is not a transaction block.
return {"block_spends_with_conditions": []}

flags = get_flags_for_height_and_constants(full_block.height, self.service.constants)
prev_tx_height = pre_sp_tx_block_height(
constants=self.service.constants,
blocks=self.service.blockchain,
prev_b_hash=full_block.prev_header_hash,
sp_index=full_block.reward_chain_block.signage_point_index,
first_in_sub_slot=len(full_block.finished_sub_slots) > 0,
)
flags = get_flags_for_height_and_constants(prev_tx_height, self.service.constants)
spends_with_conditions = await asyncio.get_running_loop().run_in_executor(
self.executor,
get_spends_for_trusted_block_with_conditions,
Expand Down Expand Up @@ -792,12 +807,19 @@ async def get_puzzle_and_solution(self, request: dict[str, Any]) -> EndpointResu
assert block_generator is not None

try:
prev_tx_height = pre_sp_tx_block_height(
constants=self.service.constants,
blocks=self.service.blockchain,
prev_b_hash=block.prev_header_hash,
sp_index=block.reward_chain_block.signage_point_index,
first_in_sub_slot=len(block.finished_sub_slots) > 0,
)
puzzle, solution = get_puzzle_and_solution_for_coin(
block_generator.program,
block_generator.generator_refs,
self.service.constants.MAX_BLOCK_COST_CLVM,
coin_record.coin,
get_flags_for_height_and_constants(block.height, self.service.constants),
get_flags_for_height_and_constants(prev_tx_height, self.service.constants),
)
return {"coin_solution": CoinSpend(coin_record.coin, puzzle, solution)}
except Exception as e:
Expand Down
20 changes: 10 additions & 10 deletions chia/full_node/mempool.py
Original file line number Diff line number Diff line change
Expand Up @@ -505,15 +505,15 @@ def at_full_capacity(self, cost: int) -> bool:
def create_block_generator(
self,
constants: ConsensusConstants,
height: uint32,
prev_tx_height: uint32,
timeout: float,
) -> Optional[NewBlockGenerator]:
"""
height is needed in case we fast-forward a transaction and we need to
re-run its puzzle.
prev_tx_height is needed in case we fast-forward a transaction and we
need to re-run its puzzle.
"""

mempool_bundle = self.create_bundle_from_mempool_items(constants, height, timeout)
mempool_bundle = self.create_bundle_from_mempool_items(constants, prev_tx_height, timeout)
if mempool_bundle is None:
return None

Expand All @@ -535,7 +535,7 @@ def create_block_generator(
f"spends: {len(removals)} additions: {len(additions)}",
)

flags = get_flags_for_height_and_constants(height, constants) | MEMPOOL_MODE | DONT_VALIDATE_SIGNATURE
flags = get_flags_for_height_and_constants(prev_tx_height, constants) | MEMPOOL_MODE | DONT_VALIDATE_SIGNATURE

err, conds = run_block_generator2(
block_program,
Expand All @@ -551,7 +551,7 @@ def create_block_generator(
if err is not None: # pragma: no cover
log.error(
f"Failed to compute block cost during farming: {err} "
f"height: {height} "
f"prev-tx-height: {prev_tx_height} "
f"generator: {bytes(block_program).hex()}"
)
return None
Expand All @@ -570,7 +570,7 @@ def create_block_generator(
)

def create_bundle_from_mempool_items(
self, constants: ConsensusConstants, height: uint32, timeout: float = 1.0
self, constants: ConsensusConstants, prev_tx_height: uint32, timeout: float = 1.0
) -> Optional[tuple[SpendBundle, list[Coin]]]:
cost_sum = 0 # Checks that total cost does not exceed block maximum
fee_sum = 0 # Checks that total fees don't exceed 64 bits
Expand Down Expand Up @@ -624,7 +624,7 @@ def create_bundle_from_mempool_items(
cost_saving = 0
else:
bundle_coin_spends = singleton_ff.process_fast_forward_spends(
mempool_item=item, height=height, constants=constants
mempool_item=item, prev_tx_height=prev_tx_height, constants=constants
)
unique_coin_spends, cost_saving, unique_additions = dedup_coin_spends.get_deduplication_info(
bundle_coin_spends=bundle_coin_spends
Expand Down Expand Up @@ -687,7 +687,7 @@ def create_bundle_from_mempool_items(
return agg, additions

def create_block_generator2(
self, constants: ConsensusConstants, height: uint32, timeout: float
self, constants: ConsensusConstants, prev_tx_height: uint32, timeout: float
) -> Optional[NewBlockGenerator]:
fee_sum = 0 # Checks that total fees don't exceed 64 bits
additions: list[Coin] = []
Expand Down Expand Up @@ -723,7 +723,7 @@ def create_block_generator2(
assert item.conds is not None
cost = item.conds.condition_cost + item.conds.execution_cost
bundle_coin_spends = singleton_ff.process_fast_forward_spends(
mempool_item=item, height=height, constants=constants
mempool_item=item, prev_tx_height=prev_tx_height, constants=constants
)
unique_coin_spends, cost_saving, unique_additions = dedup_coin_spends.get_deduplication_info(
bundle_coin_spends=bundle_coin_spends
Expand Down
2 changes: 2 additions & 0 deletions chia/full_node/mempool_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,8 @@ class MempoolManager:
# cache of MempoolItems with height conditions making them not valid yet
_pending_cache: PendingTxCache
seen_cache_size: int
# the peak is only ever set to a transaction block. We use it to validate
# timelocks against, so it must have a timestamp.
peak: Optional[BlockRecordProtocol]
mempool: Mempool
_worker_queue_size: int
Expand Down
Loading