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
22 changes: 22 additions & 0 deletions hathor/builder/resources_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
from hathor.event.resources.event import EventResource
from hathor.exception import BuilderError
from hathor.feature_activation.feature_service import FeatureService
from hathor.nanocontracts.resources.builtin import BlueprintBuiltinResource
from hathor.nanocontracts.resources.nc_creation import NCCreationResource
from hathor.nanocontracts.resources.on_chain import BlueprintOnChainResource
from hathor.prometheus import PrometheusMetricsExporter

if TYPE_CHECKING:
Expand Down Expand Up @@ -250,6 +253,25 @@ def create_resources(self) -> server.Site:
(b'utxo_search', UtxoSearchResource(self.manager), root),
])

if settings.ENABLE_NANO_CONTRACTS:
from hathor.nanocontracts.resources import (
BlueprintInfoResource,
BlueprintSourceCodeResource,
NanoContractHistoryResource,
NanoContractStateResource,
)
nc_resource = Resource()
root.putChild(b'nano_contract', nc_resource)
blueprint_resource = Resource()
nc_resource.putChild(b'blueprint', blueprint_resource)
blueprint_resource.putChild(b'info', BlueprintInfoResource(self.manager))
blueprint_resource.putChild(b'builtin', BlueprintBuiltinResource(self.manager))
blueprint_resource.putChild(b'on_chain', BlueprintOnChainResource(self.manager))
blueprint_resource.putChild(b'source', BlueprintSourceCodeResource(self.manager))
nc_resource.putChild(b'history', NanoContractHistoryResource(self.manager))
nc_resource.putChild(b'state', NanoContractStateResource(self.manager))
nc_resource.putChild(b'creation', NCCreationResource(self.manager))

if self._args.enable_debug_api:
debug_resource = Resource()
root.putChild(b'_debug', debug_resource)
Expand Down
153 changes: 140 additions & 13 deletions hathor/cli/events_simulator/scenario.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@
# limitations under the License.

from enum import Enum
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Optional

if TYPE_CHECKING:
from hathor.dag_builder.artifacts import DAGArtifacts
from hathor.manager import HathorManager
from hathor.simulator import Simulator

Expand All @@ -29,8 +30,10 @@ class Scenario(Enum):
INVALID_MEMPOOL_TRANSACTION = 'INVALID_MEMPOOL_TRANSACTION'
EMPTY_SCRIPT = 'EMPTY_SCRIPT'
CUSTOM_SCRIPT = 'CUSTOM_SCRIPT'
NC_EVENTS = 'NC_EVENTS'
NC_EVENTS_REORG = 'NC_EVENTS_REORG'

def simulate(self, simulator: 'Simulator', manager: 'HathorManager') -> None:
def simulate(self, simulator: 'Simulator', manager: 'HathorManager') -> Optional['DAGArtifacts']:
simulate_fns = {
Scenario.ONLY_LOAD: simulate_only_load,
Scenario.SINGLE_CHAIN_ONE_BLOCK: simulate_single_chain_one_block,
Expand All @@ -40,24 +43,31 @@ def simulate(self, simulator: 'Simulator', manager: 'HathorManager') -> None:
Scenario.INVALID_MEMPOOL_TRANSACTION: simulate_invalid_mempool_transaction,
Scenario.EMPTY_SCRIPT: simulate_empty_script,
Scenario.CUSTOM_SCRIPT: simulate_custom_script,
Scenario.NC_EVENTS: simulate_nc_events,
Scenario.NC_EVENTS_REORG: simulate_nc_events_reorg,
}

simulate_fn = simulate_fns[self]

simulate_fn(simulator, manager)
return simulate_fn(simulator, manager)


def simulate_only_load(simulator: 'Simulator', _manager: 'HathorManager') -> None:
def simulate_only_load(simulator: 'Simulator', _manager: 'HathorManager') -> Optional['DAGArtifacts']:
simulator.run(60)
return None


def simulate_single_chain_one_block(simulator: 'Simulator', manager: 'HathorManager') -> None:
def simulate_single_chain_one_block(simulator: 'Simulator', manager: 'HathorManager') -> Optional['DAGArtifacts']:
from hathor.simulator.utils import add_new_blocks
add_new_blocks(manager, 1)
simulator.run(60)
return None


def simulate_single_chain_blocks_and_transactions(simulator: 'Simulator', manager: 'HathorManager') -> None:
def simulate_single_chain_blocks_and_transactions(
simulator: 'Simulator',
manager: 'HathorManager',
) -> Optional['DAGArtifacts']:
from hathor.conf.get_settings import get_global_settings
from hathor.simulator.utils import add_new_blocks, gen_new_tx

Expand All @@ -83,8 +93,10 @@ def simulate_single_chain_blocks_and_transactions(simulator: 'Simulator', manage
add_new_blocks(manager, 1)
simulator.run(60)

return None

def simulate_reorg(simulator: 'Simulator', manager: 'HathorManager') -> None:

def simulate_reorg(simulator: 'Simulator', manager: 'HathorManager') -> Optional['DAGArtifacts']:
from hathor.simulator import FakeConnection
from hathor.simulator.utils import add_new_blocks

Expand All @@ -101,8 +113,10 @@ def simulate_reorg(simulator: 'Simulator', manager: 'HathorManager') -> None:
simulator.add_connection(connection)
simulator.run(60)

return None


def simulate_unvoided_transaction(simulator: 'Simulator', manager: 'HathorManager') -> None:
def simulate_unvoided_transaction(simulator: 'Simulator', manager: 'HathorManager') -> Optional['DAGArtifacts']:
from hathor.conf.get_settings import get_global_settings
from hathor.simulator.utils import add_new_block, add_new_blocks, gen_new_tx

Expand Down Expand Up @@ -147,13 +161,14 @@ def simulate_unvoided_transaction(simulator: 'Simulator', manager: 'HathorManage
assert tx.get_metadata().voided_by
assert not tx2.get_metadata().voided_by

return None

def simulate_invalid_mempool_transaction(simulator: 'Simulator', manager: 'HathorManager') -> None:
from hathor.conf.get_settings import get_global_settings

def simulate_invalid_mempool_transaction(simulator: 'Simulator', manager: 'HathorManager') -> Optional['DAGArtifacts']:
from hathor.simulator.utils import add_new_blocks, gen_new_tx
from hathor.transaction import Block

settings = get_global_settings()
settings = manager._settings
assert manager.wallet is not None
address = manager.wallet.get_unused_address(mark_as_used=False)

Expand Down Expand Up @@ -186,8 +201,10 @@ def simulate_invalid_mempool_transaction(simulator: 'Simulator', manager: 'Hatho
balance_per_address = manager.wallet.get_balance_per_address(settings.HATHOR_TOKEN_UID)
assert balance_per_address[address] == 6400

return None


def simulate_empty_script(simulator: 'Simulator', manager: 'HathorManager') -> None:
def simulate_empty_script(simulator: 'Simulator', manager: 'HathorManager') -> Optional['DAGArtifacts']:
from hathor.conf.get_settings import get_global_settings
from hathor.simulator.utils import add_new_blocks, gen_new_tx
from hathor.transaction import TxInput, TxOutput
Expand Down Expand Up @@ -218,8 +235,10 @@ def simulate_empty_script(simulator: 'Simulator', manager: 'HathorManager') -> N
add_new_blocks(manager, 1)
simulator.run(60)

return None

def simulate_custom_script(simulator: 'Simulator', manager: 'HathorManager') -> None:

def simulate_custom_script(simulator: 'Simulator', manager: 'HathorManager') -> Optional['DAGArtifacts']:
from hathor.conf.get_settings import get_global_settings
from hathor.simulator.utils import add_new_blocks, gen_new_tx
from hathor.transaction import TxInput, TxOutput
Expand Down Expand Up @@ -255,3 +274,111 @@ def simulate_custom_script(simulator: 'Simulator', manager: 'HathorManager') ->

add_new_blocks(manager, 1)
simulator.run(60)

return None


def simulate_nc_events(simulator: 'Simulator', manager: 'HathorManager') -> Optional['DAGArtifacts']:
from hathor.nanocontracts import Blueprint, NCFail, public
from hathor.nanocontracts.catalog import NCBlueprintCatalog
from hathor.nanocontracts.context import Context
from hathor.nanocontracts.types import ContractId
from tests.dag_builder.builder import TestDAGBuilder # skip-import-tests-custom-check

class TestEventsBlueprint1(Blueprint):
@public
def initialize(self, ctx: Context) -> None:
self.syscall.emit_event(b'test event on initialize 1')

@public
def fail(self, ctx: Context) -> None:
# This will not be emitted because the tx will fail.
self.syscall.emit_event(b'test event on fail')
raise NCFail

@public
def call_another(self, ctx: Context, contract_id: ContractId) -> None:
self.syscall.emit_event(b'test event on call_another')
self.syscall.call_public_method(contract_id, 'some_method', [])

class TestEventsBlueprint2(Blueprint):
@public
def initialize(self, ctx: Context) -> None:
self.syscall.emit_event(b'test event on initialize 2')

@public
def some_method(self, ctx: Context) -> None:
self.syscall.emit_event(b'test event on some_method')

blueprint1_id = b'\x11' * 32
blueprint2_id = b'\x22' * 32
manager.tx_storage.nc_catalog = NCBlueprintCatalog({
blueprint1_id: TestEventsBlueprint1,
blueprint2_id: TestEventsBlueprint2,
})
dag_builder = TestDAGBuilder.from_manager(manager)
artifacts = dag_builder.build_from_str(f'''
blockchain genesis b[1..3]
b1 < dummy

# test simple event
nc1.nc_id = "{blueprint1_id.hex()}"
nc1.nc_method = initialize()

nc2.nc_id = "{blueprint2_id.hex()}"
nc2.nc_method = initialize()

# test events across contracts
nc3.nc_id = nc1
nc3.nc_method = call_another(`nc2`)

# test NC failure
nc4.nc_id = nc1
nc4.nc_method = fail()

nc1 <-- nc2 <-- nc3 <-- nc4
nc2 <-- b2
nc4 <-- b3
nc4 < b2
''')
artifacts.propagate_with(manager, up_to='b2')
simulator.run(1)
artifacts.propagate_with(manager)
simulator.run(1)

return artifacts


def simulate_nc_events_reorg(simulator: 'Simulator', manager: 'HathorManager') -> Optional['DAGArtifacts']:
from hathor.nanocontracts import Blueprint, public
from hathor.nanocontracts.catalog import NCBlueprintCatalog
from hathor.nanocontracts.context import Context
from tests.dag_builder.builder import TestDAGBuilder # skip-import-tests-custom-check

class TestEventsBlueprint1(Blueprint):
@public
def initialize(self, ctx: Context) -> None:
self.syscall.emit_event(b'test event on initialize 1')

blueprint1_id = b'\x11' * 32
manager.tx_storage.nc_catalog = NCBlueprintCatalog({blueprint1_id: TestEventsBlueprint1})
dag_builder = TestDAGBuilder.from_manager(manager)

# 2 reorgs happen, so nc1.initialize() gets executed 3 times, once in block a2 and twice in block b2
artifacts = dag_builder.build_from_str(f'''
blockchain genesis b[1..4]
blockchain b1 a[2..3]
b1 < dummy
b2 < a2 < a3 < b3 < b4

nc1.nc_id = "{blueprint1_id.hex()}"
nc1.nc_method = initialize()

nc1 <-- b2
nc1 <-- a2
''')

artifacts.propagate_with(manager)
simulator.run(1)

return artifacts
1 change: 1 addition & 0 deletions hathor/cli/openapi_files/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def get_registered_resources() -> list[type[Resource]]:
import hathor.event.resources.event # noqa: 401
import hathor.feature_activation.resources.feature # noqa: 401
import hathor.healthcheck.resources.healthcheck # noqa: 401
import hathor.nanocontracts.resources # noqa: 401
import hathor.p2p.resources # noqa: 401
import hathor.profiler.resources # noqa: 401
import hathor.stratum.resources # noqa: 401
Expand Down
Loading
Loading