1313# limitations under the License.
1414
1515from itertools import chain
16- from typing import TYPE_CHECKING , Any , Iterable , Optional , cast
16+ from typing import TYPE_CHECKING , Any , Iterable , Optional , assert_never , cast
1717
1818from structlog import get_logger
1919
2020from hathor .conf .get_settings import get_global_settings
2121from hathor .transaction import BaseTransaction , Block , Transaction
22+ from hathor .transaction .nc_execution_state import NCExecutionState
2223from hathor .util import classproperty
2324from hathor .utils .weight import weight_to_work
2425
@@ -140,10 +141,10 @@ def _nc_execute_calls(self, block: Block, *, is_reorg: bool) -> None:
140141 tx_conflict_meta = tx_conflict .get_metadata ()
141142 assert tx_conflict_meta .first_block is None
142143 assert tx_conflict_meta .voided_by
144+ self .context .transaction_algorithm .remove_voided_by (tx , tx .hash )
143145 tx_meta .voided_by = None
144146 self .context .save (tx )
145- if tx_meta .voided_by :
146- continue
147+ tx_meta .nc_execution = NCExecutionState .PENDING
147148 nc_calls .append (tx )
148149
149150 if not nc_calls :
@@ -160,6 +161,8 @@ def _nc_execute_calls(self, block: Block, *, is_reorg: bool) -> None:
160161 if tx_meta .voided_by :
161162 # Skip voided transactions. This might happen if a previous tx in nc_calls fails and
162163 # mark this tx as voided.
164+ tx_meta .nc_execution = NCExecutionState .SKIPPED
165+ self .context .save (tx )
163166 continue
164167
165168 from hathor .nanocontracts .runner import Runner
@@ -169,6 +172,8 @@ def _nc_execute_calls(self, block: Block, *, is_reorg: bool) -> None:
169172 runner = Runner (tx .storage , storage_factory , block_trie )
170173 try :
171174 tx .execute (runner )
175+ tx_meta .nc_execution = NCExecutionState .SUCCESS
176+ self .context .save (tx )
172177 # TODO Avoid calling multiple commits for the same contract. The best would be to call the commit
173178 # method once per contract per block, just like we do for the block_trie. This ensures we will
174179 # have a clean database with no orphan nodes.
@@ -183,11 +188,28 @@ def _nc_execute_calls(self, block: Block, *, is_reorg: bool) -> None:
183188 meta .nc_block_root_id = block_trie .root .id
184189 self .context .save (block )
185190
191+ for tx in nc_calls :
192+ tx_meta = tx .get_metadata ()
193+ assert tx_meta .nc_execution is not None
194+ match tx_meta .nc_execution :
195+ case NCExecutionState .PENDING :
196+ assert False # should never happen
197+ case NCExecutionState .SUCCESS :
198+ assert tx_meta .voided_by is None
199+ case NCExecutionState .FAILURE :
200+ assert tx_meta .voided_by == {tx .hash , self ._settings .NC_EXECUTION_FAIL_ID }
201+ case NCExecutionState .SKIPPED :
202+ assert tx_meta .voided_by
203+ assert self ._settings .NC_EXECUTION_FAIL_ID not in tx_meta .voided_by
204+ case _:
205+ assert_never (tx_meta .nc_execution )
206+
186207 def mark_as_nc_fail_execution (self , tx : Transaction ) -> None :
187208 """Mark that a transaction failed execution. It also propagates its voidedness through the DAG of funds."""
188209 assert tx .storage is not None
189210 tx_meta = tx .get_metadata ()
190211 tx_meta .add_voided_by (self ._settings .NC_EXECUTION_FAIL_ID )
212+ tx_meta .nc_execution = NCExecutionState .FAILURE
191213 self .context .save (tx )
192214 self .context .transaction_algorithm .add_voided_by (tx ,
193215 tx .hash ,
0 commit comments