From a7cf1bacbc6913eec854986f6566ef1d1ed385d1 Mon Sep 17 00:00:00 2001 From: Marcelo Salhab Brogliato Date: Wed, 1 Mar 2023 00:56:08 -0600 Subject: [PATCH] feat(cli): Add feature flag and CLI parameters for Nano Contracts --- hathor/builder/cli_builder.py | 6 +++++ hathor/cli/run_node.py | 10 ++++++-- hathor/cli/run_node_args.py | 1 + hathor/conf/__init__.py | 2 ++ hathor/conf/nano_testnet.py | 38 ++++++++++++++++++++++++++++ hathor/conf/nano_testnet.yml | 20 +++++++++++++++ hathor/conf/settings.py | 26 ++++++++++++++++++- hathor/conf/unittests.py | 3 ++- hathor/conf/unittests.yml | 1 + tests/others/test_hathor_settings.py | 12 ++++++++- 10 files changed, 114 insertions(+), 5 deletions(-) create mode 100644 hathor/conf/nano_testnet.py create mode 100644 hathor/conf/nano_testnet.yml diff --git a/hathor/builder/cli_builder.py b/hathor/builder/cli_builder.py index f1303774f..af820f4c5 100644 --- a/hathor/builder/cli_builder.py +++ b/hathor/builder/cli_builder.py @@ -110,6 +110,12 @@ def create_manager(self, reactor: Reactor) -> HathorManager: reactor_type=type(reactor).__name__, ) + # XXX Remove this protection after Nano Contracts are launched. + if settings.NETWORK_NAME not in {'nano-testnet-alpha', 'unittests'}: + # Add protection to prevent enabling Nano Contracts due to misconfigurations. + self.check_or_raise(not settings.ENABLE_NANO_CONTRACTS, + 'configuration error: NanoContracts can only be enabled on localnets for now') + tx_storage: TransactionStorage event_storage: EventStorage indexes: IndexesManager diff --git a/hathor/cli/run_node.py b/hathor/cli/run_node.py index b30c3a666..363814a20 100644 --- a/hathor/cli/run_node.py +++ b/hathor/cli/run_node.py @@ -52,7 +52,11 @@ def create_parser(cls) -> ArgumentParser: parser.add_argument('--auto-hostname', action='store_true', help='Try to discover the hostname automatically') parser.add_argument('--unsafe-mode', help='Enable unsafe parameters. **NEVER USE IT IN PRODUCTION ENVIRONMENT**') - parser.add_argument('--testnet', action='store_true', help='Connect to Hathor testnet') + + netargs = parser.add_mutually_exclusive_group() + netargs.add_argument('--nano-testnet', action='store_true', help='Connect to Hathor nano-testnet') + netargs.add_argument('--testnet', action='store_true', help='Connect to Hathor testnet') + parser.add_argument('--test-mode-tx-weight', action='store_true', help='Reduces tx weight to 1 for testing purposes') parser.add_argument('--dns', action='append', help='Seed DNS') @@ -355,7 +359,7 @@ def check_python_version(self) -> None: def __init__(self, *, argv=None): from hathor.cli.run_node_args import RunNodeArgs - from hathor.conf import TESTNET_SETTINGS_FILEPATH + from hathor.conf import NANO_TESTNET_SETTINGS_FILEPATH, TESTNET_SETTINGS_FILEPATH from hathor.conf.get_settings import get_global_settings self.log = logger.new() @@ -372,6 +376,8 @@ def __init__(self, *, argv=None): os.environ['HATHOR_CONFIG_YAML'] = self._args.config_yaml elif self._args.testnet: os.environ['HATHOR_CONFIG_YAML'] = TESTNET_SETTINGS_FILEPATH + elif self._args.nano_testnet: + os.environ['HATHOR_CONFIG_YAML'] = NANO_TESTNET_SETTINGS_FILEPATH try: get_global_settings() diff --git a/hathor/cli/run_node_args.py b/hathor/cli/run_node_args.py index 3beca2b0f..fadc3521c 100644 --- a/hathor/cli/run_node_args.py +++ b/hathor/cli/run_node_args.py @@ -76,3 +76,4 @@ class RunNodeArgs(BaseModel, extra=Extra.allow): signal_not_support: set[Feature] x_asyncio_reactor: bool x_ipython_kernel: bool + nano_testnet: bool diff --git a/hathor/conf/__init__.py b/hathor/conf/__init__.py index 99dde297c..36fecbae5 100644 --- a/hathor/conf/__init__.py +++ b/hathor/conf/__init__.py @@ -20,11 +20,13 @@ MAINNET_SETTINGS_FILEPATH = str(parent_dir / 'mainnet.yml') TESTNET_SETTINGS_FILEPATH = str(parent_dir / 'testnet.yml') +NANO_TESTNET_SETTINGS_FILEPATH = str(parent_dir / 'nano_testnet.yml') UNITTESTS_SETTINGS_FILEPATH = str(parent_dir / 'unittests.yml') __all__ = [ 'MAINNET_SETTINGS_FILEPATH', 'TESTNET_SETTINGS_FILEPATH', + 'NANO_TESTNET_SETTINGS_FILEPATH', 'UNITTESTS_SETTINGS_FILEPATH', 'HathorSettings', ] diff --git a/hathor/conf/nano_testnet.py b/hathor/conf/nano_testnet.py new file mode 100644 index 000000000..32f7ab7c9 --- /dev/null +++ b/hathor/conf/nano_testnet.py @@ -0,0 +1,38 @@ +# Copyright 2022 Hathor Labs +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from hathor.conf.settings import HathorSettings + +SETTINGS = HathorSettings( + P2PKH_VERSION_BYTE=b'\x49', + MULTISIG_VERSION_BYTE=b'\x87', + NETWORK_NAME='nano-testnet-alpha', + BOOTSTRAP_DNS=[], + # Genesis stuff + GENESIS_OUTPUT_SCRIPT=bytes.fromhex('76a91478e804bf8aa68332c6c1ada274ac598178b972bf88ac'), + GENESIS_BLOCK_TIMESTAMP=1677601898, + GENESIS_BLOCK_NONCE=7881594, + GENESIS_BLOCK_HASH=bytes.fromhex('000003472f6a17c2199e24c481a4326c217d07376acd9598651f8413c008554d'), + GENESIS_TX1_NONCE=110, + GENESIS_TX1_HASH=bytes.fromhex('0008f0e9dbe6e4bbc3a85fce7494fee70011b9c7e72f5276daa2a235355ac013'), + GENESIS_TX2_NONCE=180, + GENESIS_TX2_HASH=bytes.fromhex('008d81d9d58a43fd9649f33483d804a4417247b4d4e4e01d64406c4177fee0c2'), + # tx weight parameters. With these settings, tx weight is always 8 + MIN_TX_WEIGHT_K=0, + MIN_TX_WEIGHT_COEFFICIENT=0, + MIN_TX_WEIGHT=8, + CHECKPOINTS=[], + ENABLE_NANO_CONTRACTS=True, + BLUEPRINTS={}, +) diff --git a/hathor/conf/nano_testnet.yml b/hathor/conf/nano_testnet.yml new file mode 100644 index 000000000..ece2b1b87 --- /dev/null +++ b/hathor/conf/nano_testnet.yml @@ -0,0 +1,20 @@ +P2PKH_VERSION_BYTE: x49 +MULTISIG_VERSION_BYTE: x87 +NETWORK_NAME: nano-testnet-alpha +BOOTSTRAP_DNS: [] + +# Genesis stuff +GENESIS_OUTPUT_SCRIPT: 76a91478e804bf8aa68332c6c1ada274ac598178b972bf88ac +GENESIS_BLOCK_TIMESTAMP: 1677601898 +GENESIS_BLOCK_NONCE: 7881594 +GENESIS_BLOCK_HASH: 000003472f6a17c2199e24c481a4326c217d07376acd9598651f8413c008554d +GENESIS_TX1_NONCE: 110 +GENESIS_TX1_HASH: 0008f0e9dbe6e4bbc3a85fce7494fee70011b9c7e72f5276daa2a235355ac013 +GENESIS_TX2_NONCE: 180 +GENESIS_TX2_HASH: 008d81d9d58a43fd9649f33483d804a4417247b4d4e4e01d64406c4177fee0c2 + +# tx weight parameters. With these settings tx weight is always 8 +MIN_TX_WEIGHT_K: 0 +MIN_TX_WEIGHT_COEFFICIENT: 0 +MIN_TX_WEIGHT: 8 +ENABLE_NANO_CONTRACTS: true diff --git a/hathor/conf/settings.py b/hathor/conf/settings.py index bdd441f3e..62718bf2a 100644 --- a/hathor/conf/settings.py +++ b/hathor/conf/settings.py @@ -423,6 +423,15 @@ def GENESIS_TX2_TIMESTAMP(self) -> int: OLD_MAX_MERKLE_PATH_LENGTH: int = 12 NEW_MAX_MERKLE_PATH_LENGTH: int = 20 + # Used to enable nano contracts. + # + # This should NEVER be enabled for mainnet and testnet, since both networks will + # activate Nano Contracts through the Feature Activation. + ENABLE_NANO_CONTRACTS: bool = False + + # List of enabled blueprints. + BLUEPRINTS: dict[bytes, 'str'] = {} + @classmethod def from_yaml(cls, *, filepath: str) -> 'HathorSettings': """Takes a filepath to a yaml file and returns a validated HathorSettings instance.""" @@ -449,6 +458,17 @@ def _parse_checkpoints(checkpoints: Union[dict[int, str], list[Checkpoint]]) -> return checkpoints +def _parse_blueprints(blueprints_raw: dict[str, str]) -> dict[bytes, str]: + """Parse dict[str, str] into dict[bytes, str].""" + blueprints: dict[bytes, str] = {} + for _id_str, _name in blueprints_raw.items(): + _id = bytes.fromhex(_id_str) + if _id in blueprints: + raise TypeError(f'Duplicate blueprint id: {_id_str}') + blueprints[_id] = _name + return blueprints + + def _parse_hex_str(hex_str: Union[str, bytes]) -> bytes: """Parse a raw hex string into bytes.""" if isinstance(hex_str, str): @@ -480,5 +500,9 @@ def _parse_hex_str(hex_str: Union[str, bytes]) -> bytes: _parse_checkpoints=pydantic.validator( 'CHECKPOINTS', pre=True - )(_parse_checkpoints) + )(_parse_checkpoints), + _parse_blueprints=pydantic.validator( + 'BLUEPRINTS', + pre=True + )(_parse_blueprints) ) diff --git a/hathor/conf/unittests.py b/hathor/conf/unittests.py index 0b9d46144..39e0b67e0 100644 --- a/hathor/conf/unittests.py +++ b/hathor/conf/unittests.py @@ -39,5 +39,6 @@ evaluation_interval=4, max_signal_bits=4, default_threshold=3 - ) + ), + ENABLE_NANO_CONTRACTS=True, ) diff --git a/hathor/conf/unittests.yml b/hathor/conf/unittests.yml index ebd25657d..abab9ae90 100644 --- a/hathor/conf/unittests.yml +++ b/hathor/conf/unittests.yml @@ -17,6 +17,7 @@ GENESIS_TX2_HASH: 33e14cb555a96967841dcbe0f95e9eab5810481d01de8f4f73afb8cce365e8 REWARD_SPEND_MIN_BLOCKS: 10 SLOW_ASSERTS: true MAX_TX_WEIGHT_DIFF_ACTIVATION: 0.0 +ENABLE_NANO_CONTRACTS: true FEATURE_ACTIVATION: evaluation_interval: 4 diff --git a/tests/others/test_hathor_settings.py b/tests/others/test_hathor_settings.py index 12040a0ca..3994e2a42 100644 --- a/tests/others/test_hathor_settings.py +++ b/tests/others/test_hathor_settings.py @@ -18,8 +18,14 @@ from pydantic import ValidationError from hathor.checkpoint import Checkpoint -from hathor.conf import MAINNET_SETTINGS_FILEPATH, TESTNET_SETTINGS_FILEPATH, UNITTESTS_SETTINGS_FILEPATH +from hathor.conf import ( + MAINNET_SETTINGS_FILEPATH, + NANO_TESTNET_SETTINGS_FILEPATH, + TESTNET_SETTINGS_FILEPATH, + UNITTESTS_SETTINGS_FILEPATH, +) from hathor.conf.mainnet import SETTINGS as MAINNET_SETTINGS +from hathor.conf.nano_testnet import SETTINGS as NANO_TESTNET_SETTINGS from hathor.conf.settings import HathorSettings from hathor.conf.testnet import SETTINGS as TESTNET_SETTINGS from hathor.conf.unittests import SETTINGS as UNITTESTS_SETTINGS @@ -115,3 +121,7 @@ def test_testnet_settings_migration(): def test_unittests_settings_migration(): assert UNITTESTS_SETTINGS == HathorSettings.from_yaml(filepath=UNITTESTS_SETTINGS_FILEPATH) + + +def test_nano_testnet_settings_migration(): + assert NANO_TESTNET_SETTINGS == HathorSettings.from_yaml(filepath=NANO_TESTNET_SETTINGS_FILEPATH)