1919import hashlib
2020import traceback
2121from dataclasses import dataclass
22- from typing import TYPE_CHECKING , Iterator
22+ from typing import TYPE_CHECKING , Callable , Iterator
2323
2424from hathor .nanocontracts .exception import NCFail
2525from hathor .transaction import Block , Transaction
2626from hathor .transaction .exceptions import TokenNotFound
27- from hathor .transaction .nc_execution_state import NCExecutionState
27+
28+ # Type alias for the skip predicate
29+ ShouldSkipPredicate = Callable [[Transaction ], bool ]
2830
2931if TYPE_CHECKING :
3032 from hathor .conf .settings import HathorSettings
@@ -132,6 +134,8 @@ def __init__(
132134 def execute_block (
133135 self ,
134136 block : Block ,
137+ * ,
138+ should_skip : ShouldSkipPredicate ,
135139 ) -> Iterator [NCBlockEffect ]:
136140 """Execute block as generator, yielding effects without applying them.
137141
@@ -140,18 +144,17 @@ def execute_block(
140144
141145 Args:
142146 block: The block to execute.
147+ should_skip: A predicate function that determines if a transaction should be skipped.
148+ This allows the caller to provide context-specific voided state tracking.
143149
144150 Yields:
145151 NCBlockEffect instances representing each step of execution.
146152 """
147- from hathor .nanocontracts import NC_EXECUTION_FAIL_ID
148-
149153 assert self ._settings .ENABLE_NANO_CONTRACTS
150154 assert not block .is_genesis , "Genesis blocks should be handled separately"
151155
152156 meta = block .get_metadata ()
153157 assert not meta .voided_by
154- assert meta .nc_block_root_id is None
155158
156159 parent = block .get_block_parent ()
157160 parent_meta = parent .get_metadata ()
@@ -162,10 +165,6 @@ def execute_block(
162165 for tx in block .iter_transactions_in_this_block ():
163166 if not tx .is_nano_contract ():
164167 continue
165- tx_meta = tx .get_metadata ()
166- assert tx_meta .nc_execution in {None , NCExecutionState .PENDING }
167- if tx_meta .voided_by :
168- assert NC_EXECUTION_FAIL_ID not in tx_meta .voided_by
169168 nc_calls .append (tx )
170169
171170 nc_sorted_calls = self ._nc_calls_sorter (block , nc_calls ) if nc_calls else []
@@ -193,6 +192,7 @@ def execute_block(
193192 tx = tx ,
194193 block_storage = block_storage ,
195194 rng_seed = rng_seed ,
195+ should_skip = should_skip ,
196196 )
197197 yield result
198198
@@ -212,18 +212,24 @@ def execute_transaction(
212212 tx : Transaction ,
213213 block_storage : 'NCBlockStorage' ,
214214 rng_seed : bytes ,
215+ should_skip : ShouldSkipPredicate ,
215216 ) -> NCTxExecutionResult :
216217 """Execute a single NC transaction.
217218
218219 This method is pure and side-effect free. It does not persist anything,
219220 does not call callbacks, and returns all information needed by the caller
220- to handle success/failure cases."""
221+ to handle success/failure cases.
222+
223+ Args:
224+ tx: The transaction to execute.
225+ block_storage: The block storage for this execution context.
226+ rng_seed: The RNG seed for this transaction.
227+ should_skip: Predicate to determine if transaction should be skipped.
228+ """
221229 from hathor .nanocontracts .types import Address
222230
223- tx_meta = tx .get_metadata ()
224- if tx_meta .voided_by :
225- # Skip voided transactions. This might happen if a previous tx in nc_calls fails and
226- # mark this tx as voided.
231+ if should_skip (tx ):
232+ # Skip transactions based on the caller-provided predicate.
227233 # Check if seqnum needs to be updated.
228234 nc_header = tx .get_nano_header ()
229235 nc_address = Address (nc_header .nc_address )
0 commit comments