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
8 changes: 6 additions & 2 deletions hathor/conf/mainnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,10 @@
'000045ecbab77c9a8d819ff6d26893b9da2774eee5539f17d8fc2394f82b758e',
])),
ENABLE_NANO_CONTRACTS=NanoContractsSetting.FEATURE_ACTIVATION,
NC_ON_CHAIN_BLUEPRINT_ALLOWED_ADDRESSES=[
'HDkKGHwDHTuUGbhET73XdTJZkS8uU7PHf9',
'HUbxYhtqW8pdRCC2WngPxN7MB4SUMDPrrh',
],
FEATURE_ACTIVATION=FeatureActivationSettings(
features={
Feature.INCREASE_MAX_MERKLE_PATH_LENGTH: Criteria(
Expand Down Expand Up @@ -246,8 +250,8 @@
# Expected to be reached around Tuesday, 2025-08-12 17:39:56 GMT
# Right now the best block is 5_748_286 at Wednesday, 2025-08-06 16:02:56 GMT
start_height=5_947_200,
timeout_height=6_350_400, # N + 10 * 20160 (10 weeks after the start)
minimum_activation_height=6_027_840,
timeout_height=6_350_400, # 20 weeks
minimum_activation_height=6_048_000, # 5 weeks
lock_in_on_timeout=False,
version='0.67.0',
signal_support_by_default=True,
Expand Down
8 changes: 6 additions & 2 deletions hathor/conf/mainnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,6 @@ SOFT_VOIDED_TX_IDS:
- 00004305882eb3eef6b45f025ff58eb7baa5ca35f7d6f42c8b085482b00474e6
- 000045ecbab77c9a8d819ff6d26893b9da2774eee5539f17d8fc2394f82b758e

ENABLE_NANO_CONTRACTS: feature_activation
FEATURE_ACTIVATION:
features:
INCREASE_MAX_MERKLE_PATH_LENGTH:
Expand Down Expand Up @@ -226,7 +225,12 @@ FEATURE_ACTIVATION:
# Right now the best block is 5_947_110 at Tuesday, 2025-10-14 20:01:09 GMT
start_height: 5_947_200
timeout_height: 6_350_400 # 20 weeks
minimum_activation_height: 6_027_840 # 4 weeks
minimum_activation_height: 6_048_000 # 5 weeks
lock_in_on_timeout: false
version: 0.67.0
signal_support_by_default: true

ENABLE_NANO_CONTRACTS: feature_activation
NC_ON_CHAIN_BLUEPRINT_ALLOWED_ADDRESSES:
- HDkKGHwDHTuUGbhET73XdTJZkS8uU7PHf9
- HUbxYhtqW8pdRCC2WngPxN7MB4SUMDPrrh
9 changes: 9 additions & 0 deletions hathor/consensus/consensus.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,17 @@ def unsafe_update(self, base: BaseTransaction) -> None:
assert isinstance(old_best_block, Block)
new_best_block = base.storage.get_transaction(new_best_tip)
reorg_size = old_best_block.get_height() - context.reorg_info.common_block.get_height()
# TODO: After we remove block ties, should the assert below be true?
# assert old_best_block.get_metadata().voided_by
assert old_best_block != new_best_block
assert reorg_size > 0
self.log.info(
'reorg detected',
reorg_size=reorg_size,
previous_best_block=old_best_block.hash_hex,
new_best_block=new_best_block.hash_hex,
common_block=context.reorg_info.common_block.hash_hex,
)
context.pubsub.publish(
HathorEvents.REORG_STARTED,
old_best_height=best_height,
Expand Down
14 changes: 1 addition & 13 deletions hathor/dag_builder/artifacts.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

from hathor.dag_builder.types import DAGNode
from hathor.manager import HathorManager
from hathor.verification.verification_params import VerificationParams

if TYPE_CHECKING:
from hathor.transaction import BaseTransaction
Expand Down Expand Up @@ -60,7 +59,6 @@ def propagate_with(
*,
up_to: str | None = None,
up_to_before: str | None = None,
new_relayed_vertex: bool = False
) -> None:
"""
Propagate vertices using the provided manager up to the provided node name, included. Last propagation is
Expand All @@ -82,17 +80,7 @@ def propagate_with(

if found_begin:
try:
if new_relayed_vertex:
assert manager.vertex_handler.on_new_relayed_vertex(vertex)
else:
best_block = manager.tx_storage.get_best_block()
best_block_meta = best_block.get_metadata()
params = VerificationParams(
enable_checkdatasig_count=True,
enable_nano=True,
nc_block_root_id=best_block_meta.nc_block_root_id,
)
assert manager.vertex_handler._old_on_new_vertex(vertex, params)
assert manager.vertex_handler.on_new_relayed_vertex(vertex)
except Exception as e:
raise Exception(f'failed on_new_tx({node.name})') from e
self._last_propagated = node.name
Expand Down
3 changes: 1 addition & 2 deletions hathor/nanocontracts/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from hathor.nanocontracts.exception import NCFail
from hathor.nanocontracts.on_chain_blueprint import OnChainBlueprint
from hathor.nanocontracts.runner import Runner
from hathor.nanocontracts.storage import NCMemoryStorageFactory, NCRocksDBStorageFactory, NCStorageFactory
from hathor.nanocontracts.storage import NCRocksDBStorageFactory, NCStorageFactory
from hathor.nanocontracts.types import TokenUid, VertexId, export, fallback, public, view

# Identifier used in metadata's voided_by when a Nano Contract method fails.
Expand All @@ -32,7 +32,6 @@
'Runner',
'OnChainBlueprint',
'NCFail',
'NCMemoryStorageFactory',
'NCRocksDBStorageFactory',
'NCStorageFactory',
'public',
Expand Down
19 changes: 16 additions & 3 deletions hathor/nanocontracts/blueprint_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,28 @@ def rng(self) -> NanoRNG:
return self.__runner.syscall_get_rng()

def get_contract_id(self) -> ContractId:
"""Return the contract id of this nano contract."""
"""Return the ContractId of the current nano contract."""
return self.__runner.get_current_contract_id()

def get_blueprint_id(self) -> BlueprintId:
"""Return the blueprint id of this nano contract."""
"""
Return the BlueprintId of the current nano contract.

This means that during a proxy call, this method will return the BlueprintId of the caller's blueprint,
NOT the BlueprintId of the Blueprint that owns the running code.
"""
contract_id = self.get_contract_id()
return self.__runner.get_blueprint_id(contract_id)

def get_current_code_blueprint_id(self) -> BlueprintId:
"""
Return the BlueprintId of the Blueprint that owns the currently running code.

This means that during a proxy call, this method will return the BlueprintId of the Blueprint that owns the
running code, NOT the BlueprintId of the current nano contract.
"""
return self.__runner.get_current_code_blueprint_id()

def get_balance_before_current_call(self, token_uid: TokenUid | None = None) -> Amount:
"""
Return the balance for a given token before the current call, that is,
Expand Down Expand Up @@ -233,7 +247,6 @@ def get_proxy(self, blueprint_id: BlueprintId) -> ProxyAccessor:
Get a proxy accessor for the given blueprint ID. Use this for interacting with another blueprint via a proxy.
"""
from hathor.nanocontracts.proxy_accessor import ProxyAccessor
self.__runner.forbid_call_on_view('get_proxy')
return ProxyAccessor(runner=self.__runner, blueprint_id=blueprint_id)

def setup_new_contract(
Expand Down
67 changes: 67 additions & 0 deletions hathor/nanocontracts/proxy_accessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ def get_blueprint_id(self) -> BlueprintId:
"""Return the blueprint id of this proxy."""
return self.__blueprint_id

def view(self) -> Any:
"""Prepare a call to a proxy view method."""
return PreparedProxyViewCall(
runner=self.__runner,
blueprint_id=self.__blueprint_id,
)

def public(self, *actions: NCAction, fees: Sequence[NCFee] | None = None, forbid_fallback: bool = False) -> Any:
"""Prepare a proxy call to a public method."""
return PreparedProxyPublicCall(
Expand All @@ -55,6 +62,14 @@ def public(self, *actions: NCAction, fees: Sequence[NCFee] | None = None, forbid
forbid_fallback=forbid_fallback,
)

def get_view_method(self, method_name: str) -> ProxyViewMethodAccessor:
"""Get a proxy view method."""
return ProxyViewMethodAccessor(
runner=self.__runner,
blueprint_id=self.__blueprint_id,
method_name=method_name,
)

def get_public_method(
self,
method_name: str,
Expand All @@ -73,6 +88,26 @@ def get_public_method(
)


@final
class PreparedProxyViewCall(FauxImmutable):
__slots__ = ('__runner', '__blueprint_id')
__skip_faux_immutability_validation__ = True # Needed to implement __getattr__

def __init__(self, *, runner: Runner, blueprint_id: BlueprintId) -> None:
self.__runner: Runner
self.__blueprint_id: BlueprintId

__set_faux_immutable__(self, '__runner', runner)
__set_faux_immutable__(self, '__blueprint_id', blueprint_id)

def __getattr__(self, method_name: str) -> ProxyViewMethodAccessor:
return ProxyViewMethodAccessor(
runner=self.__runner,
blueprint_id=self.__blueprint_id,
method_name=method_name,
)


@final
class PreparedProxyPublicCall(FauxImmutable):
__slots__ = (
Expand Down Expand Up @@ -128,6 +163,38 @@ def __getattr__(self, method_name: str) -> ProxyPublicMethodAccessor:
)


@final
class ProxyViewMethodAccessor(FauxImmutable):
"""
This class represents a "proxy view method", or a proxy view method accessor, during a blueprint method execution.
It's a callable that will forward the call to the actual wrapped blueprint via syscall.
It may be used multiple times to call the same method with different arguments.
"""
__slots__ = ('__runner', '__blueprint_id', '__method_name')

def __init__(self, *, runner: Runner, blueprint_id: BlueprintId, method_name: str) -> None:
self.__runner: Runner
self.__blueprint_id: BlueprintId
self.__method_name: str

__set_faux_immutable__(self, '__runner', runner)
__set_faux_immutable__(self, '__blueprint_id', blueprint_id)
__set_faux_immutable__(self, '__method_name', method_name)

def call(self, *args: Any, **kwargs: Any) -> object:
"""Call the method with the provided arguments. This is just an alias for calling the object directly."""
return self(*args, **kwargs)

def __call__(self, *args: Any, **kwargs: Any) -> object:
"""Call the method with the provided arguments."""
return self.__runner.syscall_proxy_call_view_method(
blueprint_id=self.__blueprint_id,
method_name=self.__method_name,
args=args,
kwargs=kwargs,
)


@final
class ProxyPublicMethodAccessor(FauxImmutable):
"""
Expand Down
4 changes: 3 additions & 1 deletion hathor/nanocontracts/runner/index_records.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,12 @@ def to_json(self) -> dict[str, Any]:

@classmethod
def from_json(cls, json_dict: dict[str, Any]) -> Self:
token_version = TokenVersion(json_dict['token_version'])
assert token_version in (TokenVersion.DEPOSIT, TokenVersion.FEE)
return cls(
token_uid=TokenUid(VertexId(bytes.fromhex(json_dict['token_uid']))),
amount=json_dict['amount'],
token_version=json_dict['token_version'],
token_version=token_version, # type: ignore[arg-type]
token_name=json_dict['token_name'],
token_symbol=json_dict['token_symbol'],
)
Expand Down
Loading
Loading