diff --git a/hathor/nanocontracts/resources/nc_creation.py b/hathor/nanocontracts/resources/nc_creation.py index 519936276..dbaee6e6b 100644 --- a/hathor/nanocontracts/resources/nc_creation.py +++ b/hathor/nanocontracts/resources/nc_creation.py @@ -20,8 +20,10 @@ from hathor.api_util import Resource, set_cors from hathor.cli.openapi_files.register import register_resource from hathor.manager import HathorManager +from hathor.nanocontracts.exception import NanoContractDoesNotExist from hathor.nanocontracts.resources.on_chain import SortOrder from hathor.nanocontracts.types import BlueprintId, VertexId +from hathor.transaction import Transaction from hathor.transaction.storage.exceptions import TransactionDoesNotExist from hathor.util import bytes_from_hex, collect_n, not_none from hathor.utils.api import ErrorResponse, QueryParams, Response @@ -136,8 +138,13 @@ def render_GET(self, request: Request) -> bytes: ) iter_nc_ids = iter_getter2(tx_start=ref_tx) - iter_ncs = map(self._get_nc_creation_item_strict, iter_nc_ids) - nc_txs, has_more = collect_n(iter_ncs, params.count) + nc_id_txs, has_more = collect_n(iter_nc_ids, params.count) + nc_txs = [] + for nc_id in nc_id_txs: + item = self._get_nc_creation_item(nc_id) + if item is not None: + nc_txs.append(item) + response = NCCreationResponse( nc_creation_txs=nc_txs, before=params.before, @@ -147,7 +154,9 @@ def render_GET(self, request: Request) -> bytes: ) return response.json_dumpb() - def _get_nc_creation_item(self, nc_id: bytes) -> NCCreationItem | None: + def _try_get_contract_creation_vertex(self, nc_id: bytes) -> Transaction | None: + """Return a contract creation vertex if it exists. Otherwise, return None. + """ try: tx = self.tx_storage.get_transaction(nc_id) except TransactionDoesNotExist: @@ -156,7 +165,6 @@ def _get_nc_creation_item(self, nc_id: bytes) -> NCCreationItem | None: if not tx.is_nano_contract(): return None - from hathor.transaction import Transaction if not isinstance(tx, Transaction): return None @@ -164,8 +172,25 @@ def _get_nc_creation_item(self, nc_id: bytes) -> NCCreationItem | None: if not nano_header.is_creating_a_new_contract(): return None - blueprint_id = BlueprintId(VertexId(nano_header.nc_id)) - blueprint_class = self.tx_storage.get_blueprint_class(blueprint_id) + return tx + + def _get_nc_creation_item(self, nc_id: bytes) -> NCCreationItem | None: + tx = self._try_get_contract_creation_vertex(nc_id) + if tx is not None: + nano_header = tx.get_nano_header() + blueprint_id = BlueprintId(VertexId(nano_header.nc_id)) + blueprint_class = self.tx_storage.get_blueprint_class(blueprint_id) + created_at = tx.timestamp + + else: + try: + nc_storage = self.manager.get_best_block_nc_storage(nc_id) + except NanoContractDoesNotExist: + return None + + blueprint_id = nc_storage.get_blueprint_id() + blueprint_class = self.tx_storage.get_blueprint_class(blueprint_id) + created_at = 0 assert self.nc_history_index is not None return NCCreationItem( @@ -174,7 +199,7 @@ def _get_nc_creation_item(self, nc_id: bytes) -> NCCreationItem | None: blueprint_name=blueprint_class.__name__, last_tx_timestamp=not_none(self.nc_history_index.get_last_tx_timestamp(nc_id)), total_txs=self.nc_history_index.get_transaction_count(nc_id), - created_at=tx.timestamp, + created_at=created_at, ) def _get_nc_creation_item_strict(self, nc_id: bytes) -> NCCreationItem: diff --git a/tests/nanocontracts/test_blueprints/test_blueprint1.py b/tests/nanocontracts/test_blueprints/test_blueprint1.py index 5e784f617..dd9d1c7dc 100644 --- a/tests/nanocontracts/test_blueprints/test_blueprint1.py +++ b/tests/nanocontracts/test_blueprints/test_blueprint1.py @@ -24,3 +24,8 @@ def initialize(self, ctx: Context, a: int) -> None: @public def nop(self, ctx: Context) -> None: pass + + @public + def create_child_contract(self, ctx: Context) -> None: + blueprint_id = self.syscall.get_blueprint_id() + self.syscall.create_contract(blueprint_id, b'', [], 0) diff --git a/tests/resources/nanocontracts/test_nc_creation.py b/tests/resources/nanocontracts/test_nc_creation.py index accfda53a..3d00b7d77 100644 --- a/tests/resources/nanocontracts/test_nc_creation.py +++ b/tests/resources/nanocontracts/test_nc_creation.py @@ -45,7 +45,7 @@ def prepare_ncs(self) -> tuple[Transaction, Transaction, Transaction, Transactio password = unittest.OCB_TEST_PASSWORD.hex() dag_builder = TestDAGBuilder.from_manager(self.manager) artifacts = dag_builder.build_from_str(f''' - blockchain genesis b[1..11] + blockchain genesis b[1..12] b10 < dummy ocb1.ocb_private_key = "{private_key}" @@ -72,6 +72,8 @@ def prepare_ncs(self) -> tuple[Transaction, Transaction, Transaction, Transactio ocb1 <-- ocb2 <-- b11 b11 < nc1 < nc2 < nc3 < nc4 < nc5 + nc1 <-- nc2 <-- nc3 <-- nc4 <-- nc5 <-- b12 + ocb1.ocb_code = "{bet_code.encode().hex()}" ocb2.ocb_code = ``` from hathor import Blueprint, Context, export, public @@ -150,7 +152,7 @@ async def test_tx_aggregation(self) -> None: nc2.nc_method = initialize(0) nc3.nc_id = nc2 - nc3.nc_method = nop() + nc3.nc_method = create_child_contract() nc4.nc_id = nc1 nc4.nc_method = nop()