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
2 changes: 1 addition & 1 deletion hathor/builder/resources_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ def create_resources(self) -> server.Site:

resources = [
(b'status', StatusResource(self.manager), root),
(b'version', VersionResource(self.manager), root),
(b'version', VersionResource(self.manager, self._feature_service), root),
(b'create_tx', CreateTxResource(self.manager), root),
(b'decode_tx', DecodeTxResource(self.manager), root),
(b'validate_address', ValidateAddressResource(self.manager), root),
Expand Down
19 changes: 18 additions & 1 deletion hathor/nanocontracts/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,18 @@

import hashlib
from types import ModuleType
from typing import Callable
from typing import Callable, assert_never

from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import ec
from pycoin.key.Key import Key as PycoinKey

from hathor.conf.settings import HathorSettings, NanoContractsSetting
from hathor.crypto.util import decode_address, get_address_from_public_key_bytes, get_public_key_bytes_compressed
from hathor.feature_activation.feature import Feature
from hathor.feature_activation.feature_service import FeatureService
from hathor.nanocontracts.types import NC_METHOD_TYPE_ATTR, BlueprintId, ContractId, NCMethodType, TokenUid, VertexId
from hathor.transaction import Vertex
from hathor.transaction.headers import NanoHeader
from hathor.util import not_none

Expand Down Expand Up @@ -139,3 +143,16 @@ def sign_openssl_multisig(
signatures = [privkey.sign(data, ec.ECDSA(hashes.SHA256())) for privkey in sign_privkeys]

nano_header.nc_script = MultiSig.create_input_data(redeem_script, signatures)


def is_nano_active(settings: HathorSettings, vertex: Vertex, feature_service: FeatureService) -> bool:
"""Return whether the Nano Contracts feature is active according to the provided settings and vertex."""
match settings.ENABLE_NANO_CONTRACTS:
case NanoContractsSetting.DISABLED:
return False
case NanoContractsSetting.ENABLED:
return True
case NanoContractsSetting.FEATURE_ACTIVATION:
return feature_service.is_feature_active(vertex=vertex, feature=Feature.NANO_CONTRACTS)
case _: # pragma: no cover
assert_never(settings.ENABLE_NANO_CONTRACTS)
17 changes: 4 additions & 13 deletions hathor/verification/transaction_verifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@

from __future__ import annotations

from typing import TYPE_CHECKING, assert_never
from typing import TYPE_CHECKING

from hathor.daa import DifficultyAdjustmentAlgorithm
from hathor.feature_activation.feature import Feature
from hathor.feature_activation.feature_service import FeatureService
from hathor.profiler import get_cpu_profiler
from hathor.reward_lock import get_spent_reward_locked_info
Expand Down Expand Up @@ -267,22 +266,14 @@ def verify_sum(self, token_dict: dict[TokenUid, TokenInfo]) -> None:

def verify_version(self, tx: Transaction) -> None:
"""Verify that the vertex version is valid."""
from hathor.conf.settings import NanoContractsSetting
from hathor.nanocontracts.utils import is_nano_active
allowed_tx_versions = {
TxVersion.REGULAR_TRANSACTION,
TxVersion.TOKEN_CREATION_TRANSACTION,
}

match self._settings.ENABLE_NANO_CONTRACTS:
case NanoContractsSetting.DISABLED:
pass
case NanoContractsSetting.ENABLED:
allowed_tx_versions.add(TxVersion.ON_CHAIN_BLUEPRINT)
case NanoContractsSetting.FEATURE_ACTIVATION:
if self._feature_service.is_feature_active(vertex=tx, feature=Feature.NANO_CONTRACTS):
allowed_tx_versions.add(TxVersion.ON_CHAIN_BLUEPRINT)
case _ as unreachable:
assert_never(unreachable)
if is_nano_active(self._settings, tx, self._feature_service):
allowed_tx_versions.add(TxVersion.ON_CHAIN_BLUEPRINT)

if tx.version not in allowed_tx_versions:
raise InvalidVersionError(f'invalid vertex version: {tx.version}')
12 changes: 10 additions & 2 deletions hathor/version_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
from hathor.api_util import Resource, set_cors
from hathor.cli.openapi_files.register import register_resource
from hathor.conf.get_settings import get_global_settings
from hathor.feature_activation.feature_service import FeatureService
from hathor.manager import HathorManager
from hathor.nanocontracts.utils import is_nano_active
from hathor.util import json_dumpb


Expand All @@ -27,10 +30,12 @@ class VersionResource(Resource):
"""
isLeaf = True

def __init__(self, manager):
def __init__(self, manager: HathorManager, feature_service: FeatureService) -> None:
# Important to have the manager so we can have access to min_tx_weight_coefficient
super().__init__()
self._settings = get_global_settings()
self.manager = manager
self.feature_service = feature_service

def render_GET(self, request):
""" GET request for /version/ that returns the API version
Expand All @@ -40,10 +45,13 @@ def render_GET(self, request):
request.setHeader(b'content-type', b'application/json; charset=utf-8')
set_cors(request, 'GET')

best_block = self.manager.tx_storage.get_best_block()
nano_contracts_enabled = is_nano_active(self._settings, best_block, self.feature_service)

data = {
'version': hathor.__version__,
'network': self.manager.network,
'nano_contracts_enabled': self._settings.ENABLE_NANO_CONTRACTS,
'nano_contracts_enabled': nano_contracts_enabled,
'min_weight': self._settings.MIN_TX_WEIGHT, # DEPRECATED
'min_tx_weight': self._settings.MIN_TX_WEIGHT,
'min_tx_weight_coefficient': self._settings.MIN_TX_WEIGHT_COEFFICIENT,
Expand Down
4 changes: 2 additions & 2 deletions tests/resources/test_version.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import shutil
import subprocess
import tempfile
from unittest.mock import patch
from unittest.mock import Mock, patch

from twisted.internet.defer import inlineCallbacks

Expand All @@ -14,7 +14,7 @@
class VersionTest(_BaseResourceTest._ResourceTest):
def setUp(self):
super().setUp()
self.web = StubSite(VersionResource(self.manager))
self.web = StubSite(VersionResource(self.manager, Mock()))
self.tmp_dir = tempfile.mkdtemp()

def tearDown(self):
Expand Down