From e9e6399a658830f4be4d60be61e8838cf5613f70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jure=20=C5=BDvikart?= <7929905+jzvikart@users.noreply.github.com> Date: Mon, 9 Oct 2023 08:55:42 +0200 Subject: [PATCH 1/8] Support for creating testnet-2 --- test/integration/framework/.gitignore | 1 + .../framework/src/siftool/environments.py | 60 +++++++++++++------ .../framework/src/siftool/installers.py | 5 ++ .../framework/test/test_environments.py | 50 +++++++++++++--- 4 files changed, 90 insertions(+), 26 deletions(-) create mode 100644 test/integration/framework/src/siftool/installers.py diff --git a/test/integration/framework/.gitignore b/test/integration/framework/.gitignore index 5cc945694d..a88f54d394 100644 --- a/test/integration/framework/.gitignore +++ b/test/integration/framework/.gitignore @@ -1,4 +1,5 @@ /venv/ /build/ /src/siftool/__pycache__/ +/test/__pycache__/ /.lock diff --git a/test/integration/framework/src/siftool/environments.py b/test/integration/framework/src/siftool/environments.py index 8abdbc3bd6..579a76c54f 100644 --- a/test/integration/framework/src/siftool/environments.py +++ b/test/integration/framework/src/siftool/environments.py @@ -5,8 +5,9 @@ # Environment for load test test_many_pools_and_liquidity_providers and for testing min commission/max voting power -# Just sifnode, no ethereum -# Multi-node support +# Supports multiple sifnoded validatos, no Ethereum support yet +# +# class SifnodedEnvironment: def __init__(self, cmd: command.Command, chain_id: Optional[str] = None, sifnoded_home_root: Optional[str] = None): self.cmd = cmd @@ -28,7 +29,9 @@ def add_validator(self, /, binary: Optional[str] = None, admin_name: Optional[s staking_amount: Optional[int] = None, initial_balance: Optional[cosmos.Balance] = None, commission_rate: Optional[float] = None, commission_max_rate: Optional[float] = None, commission_max_change_rate: Optional[float] = None, min_self_delegation: Optional[int] = None, - ports: Mapping[str, int] = None, log_level: Optional[str] = None, log_file: Optional[str] = None + ports: Mapping[str, int] = None, pruning: Optional[str] = None, pruning_keep_recent: Optional[int] = None, + pruning_keep_every: Optional[int] = None, pruning_interval: Optional[int] = None, + log_level: Optional[str] = None, log_file: Optional[str] = None ): next_id = len(self.node_info) @@ -59,6 +62,10 @@ def add_validator(self, /, binary: Optional[str] = None, admin_name: Optional[s "commission_max_change_rate": commission_max_change_rate, "min_self_delegation": min_self_delegation, "ports": ports, + "pruning": pruning, + "pruning_keep_recent": pruning_keep_recent, + "pruning_keep_every": pruning_keep_every, + "pruning_interval": pruning_interval, "log_level": log_level, "log_file": log_file, } @@ -92,12 +99,11 @@ def add_validator(self, /, binary: Optional[str] = None, admin_name: Optional[s def ports_for_node(self, i: int) -> JsonDict: assert i < 10, "Change port configuration for 10 or more nodes" return { - "p2p": 10276 + i, + "api": 10131 + i, "grpc": 10909 + i, "grpc_web": 10919 + i, - "address": 10276 + i, "rpc": 10286 + i, - "api": 10131 + i, + "p2p": 10276 + i, "pprof": 10606 + i, } @@ -192,7 +198,7 @@ def start(self): self.sifnoded = sifchain.Sifnoded(self.cmd, home=self.keyring_dir, chain_id=self.chain_id, node=sifchain.format_node_url(self.node_info[0]["host"], self.node_info[0]["ports"]["rpc"]), - binary = self.node_info[0]["binary"]) + binary=self.node_info[0]["binary"]) self._state = 2 @@ -254,9 +260,20 @@ def _update_configuration_files(self, node_info, peers_node_info): app_toml = sifnoded.load_app_toml() config_toml = sifnoded.load_config_toml() app_toml["minimum-gas-prices"] = sif_format_amount(0.5, ROWAN) + if node_info["pruning"] is not None: + app_toml["pruning"] = node_info["pruning"] + if node_info["pruning_keep_recent"] is not None: + app_toml["pruning-keep-recent"] = str(node_info["pruning_keep_recent"]) + if node_info["pruning_keep_every"] is not None: + app_toml["pruning-keep-every"] = str(node_info["pruning_keep_every"]) + if node_info["pruning_interval"] is not None: + app_toml["pruning-interval"] = str(node_info["pruning_interval"]) app_toml['api']['enable'] = True - app_toml["api"]["address"] = sifchain.format_node_url(ANY_ADDR, node_info["ports"]["api"]) - config_toml["log_level"] = node_info["log_level"] # TODO Probably redundant + app_toml["api"]["address"] = sifchain.format_node_url(ANY_ADDR, node_info["ports"]["api"]) # default "tcp://0.0.0.0:1317" + app_toml["grpc"]["address"] = "{}:{}".format(ANY_ADDR, node_info["ports"]["grpc"]) # default "0.0.0.0:9090" + app_toml["grpc-web"]["address"] = "{}:{}".format(ANY_ADDR, node_info["ports"]["grpc_web"]) # default "0.0.0.0:9091" + config_toml["rpc"]["laddr"] = "tcp://{}:{}".format(ANY_ADDR, node_info["ports"]["rpc"]) # default "tcp://127.0.0.1:26657" + config_toml["p2p"]["laddr"] = "{}:{}".format(ANY_ADDR, node_info["ports"]["p2p"]) # default "tcp://0.0.0.0:26656" config_toml['p2p']["external_address"] = "{}:{}".format(node_info["host"], node_info["ports"]["p2p"]) if peers: config_toml["p2p"]["persistent_peers"] = ",".join(peers) @@ -265,6 +282,7 @@ def _update_configuration_files(self, node_info, peers_node_info): config_toml['p2p']['allow_duplicate_ip'] = True config_toml["rpc"]["pprof_laddr"] = "{}:{}".format(LOCALHOST, node_info["ports"]["pprof"]) config_toml['moniker'] = node_info["moniker"] + config_toml["log_level"] = node_info["log_level"] sifnoded.save_app_toml(app_toml) sifnoded.save_config_toml(config_toml) @@ -279,17 +297,23 @@ def _sifnoded_for(self, node_info: JsonDict, to_node_info: Optional[JsonDict] = node = sifchain.format_node_url(to_node_info["host"], to_node_info["ports"]["rpc"]) return sifchain.Sifnoded(self.cmd, binary=binary, home=home, chain_id=self.chain_id, node=node) + # Returns a Sifnoded that uses a default binary with the "keyring" profile and pointing to specific validator. + def _client_for(self, node_index: int = 0) -> sifchain.Sifnoded: + to_node_info = self.node_info[node_index] + node = sifchain.format_node_url(to_node_info["host"], to_node_info["ports"]["rpc"]) + return sifchain.Sifnoded(self.cmd, home=self.keyring_dir, chain_id=self.chain_id, node=node) + def _sifnoded_start(self, node_info: JsonDict): sifnoded = self._sifnoded_for(node_info) - ports = node_info["ports"] log_file_path = node_info["log_file"] - log_level = node_info["log_level"] log_file = open(log_file_path, "w") - process = sifnoded.sifnoded_start(log_file=log_file, log_level=log_level, trace=True, - tcp_url="tcp://{}:{}".format(ANY_ADDR, ports["rpc"]), p2p_laddr="{}:{}".format(ANY_ADDR, ports["p2p"]), - grpc_address="{}:{}".format(ANY_ADDR, ports["grpc"]), - grpc_web_address="{}:{}".format(ANY_ADDR, ports["grpc_web"]), - address="tcp://{}:{}".format(ANY_ADDR, ports["address"])) + process = sifnoded.sifnoded_start(log_file=log_file, trace=True) + # , log_level=log_level, + # address="tcp://{}:{}".format(ANY_ADDR, ports["api"]), # app.toml->api->address + # grpc_address="{}:{}".format(ANY_ADDR, ports["grpc"]), # app.toml->grpc->address + # grpc_web_address="{}:{}".format(ANY_ADDR, ports["grpc_web"]), # app.toml->grpc-web->address + # tcp_url="tcp://{}:{}".format(ANY_ADDR, ports["rpc"]), # config.toml->rpc->laddr + # p2p_laddr="{}:{}".format(ANY_ADDR, ports["p2p"])) # config.toml->p2p->laddr sifnoded._wait_up() return log_file, process @@ -334,14 +358,14 @@ def _broadcast_create_validator_msg(self, node_info: JsonDict): assert float(new_validator["commission"]["commission_rates"]["max_change_rate"]) == commission_max_change_rate def _create_validator_home(self, node_info: JsonDict): - # Create admin account. We want this account both in validator's home as well as in self.keyring_dir: + # Create admin account. We want this account both in validator's home and in self.keyring_dir: # - it has to be in validator's home because "set-genesis-oracle-admin" requires it and there is no separate # "--keyring-dir" CLI option. Otherwise, we would prefer all accounts to be separated from validator home. # - because it is also in self.keyring_dir all admin names have to be unique. admin_name = node_info["admin_name"] admin_mnemonic = node_info.get("admin_mnemonic", None) sifnoded = sifchain.Sifnoded(self.cmd, home=self.keyring_dir) - admin_acct, admin_mnemonic = sifnoded._keys_add(admin_name, mnemonic=admin_mnemonic) + admin_acct, admin_mnemonic = sifnoded._keys_add(admin_name, mnemonic=admin_mnemonic) # Creates if none given admin_addr = admin_acct["address"] node_info["admin_addr"] = admin_addr diff --git a/test/integration/framework/src/siftool/installers.py b/test/integration/framework/src/siftool/installers.py new file mode 100644 index 0000000000..ac257bb103 --- /dev/null +++ b/test/integration/framework/src/siftool/installers.py @@ -0,0 +1,5 @@ +from siftool.command import Command + +cmd = Command() + +print(repr(cmd)) diff --git a/test/integration/framework/test/test_environments.py b/test/integration/framework/test/test_environments.py index 57003de2b1..c2e14bda0e 100644 --- a/test/integration/framework/test/test_environments.py +++ b/test/integration/framework/test/test_environments.py @@ -1,4 +1,3 @@ -import contextlib from siftool.common import * from siftool import command, environments, project, sifchain, cosmos @@ -13,10 +12,31 @@ def test_transfer(env): sifnoded.send_and_check(env.faucet, sifnoded.create_addr(), {sifchain.ROWAN: 10 ** sifchain.ROWAN_DECIMALS}) -def assert_validators_working(env, expected_monikers): - assert set(get_validators(env)) == expected_monikers - for i in range(len(env.node_info)): - test_transfer(env) +def assert_validators_working(env): + expected_monikers = [node_info["moniker"] for node_info in env.node_info] + assert set(get_validators(env)) == set(expected_monikers) + number_of_nodes = len(env.node_info) + for i in range(number_of_nodes): + # Send transactions using "keyring" profile that has all the private keys, but is directed at a particular node. + # Cross check balaces on all nodes. + sifnoded = env._client_for(i) + from_address = env.faucet + to_address = sifnoded.create_addr() # This pollutes "client" keyring with temporary addresses, but we don't care + from_balance_before = sifnoded.get_balance(from_address) + to_balance_before = sifnoded.get_balance(to_address) + for j in range(number_of_nodes): + sifnoded_crosscheck = env._client_for(j) + assert cosmos.balance_equal(sifnoded_crosscheck.get_balance(from_address), from_balance_before) + assert cosmos.balance_equal(sifnoded_crosscheck.get_balance(to_address), to_balance_before) + sifnoded.send_and_check(from_address, to_address, {sifchain.ROWAN: 10 ** sifchain.ROWAN_DECIMALS}) + at_block = sifnoded.get_current_block() + from_balance_after = sifnoded.get_balance(from_address) + to_balance_after = sifnoded.get_balance(to_address) + for j in range(number_of_nodes): + sifnoded_crosscheck = env._client_for(j) + sifnoded_crosscheck.wait_for_block(at_block) # Make sure the change has propagated + assert cosmos.balance_equal(sifnoded_crosscheck.get_balance(from_address), from_balance_after) + assert cosmos.balance_equal(sifnoded_crosscheck.get_balance(to_address), to_balance_after) class TestSifnodedEnvironment: @@ -32,20 +52,34 @@ def teardown_method(self): prj = project.Project(self.cmd, project_dir()) prj.pkill() - def test_environment_setup_basic(self): + def test_environment_setup_basic_1(self): env = environments.SifnodedEnvironment(self.cmd, sifnoded_home_root=self.sifnoded_home_root) env.add_validator() env.start() - assert_validators_working(env, set("sifnoded-{}".format(i) for i in range(1))) + assert_validators_working(env) + + def test_environment_setup_basic_4(self): + env = environments.SifnodedEnvironment(self.cmd, chain_id="sifchain-testnet-2", sifnoded_home_root=self.sifnoded_home_root) + env.add_validator(moniker="ant") + env.add_validator(moniker="bee") + env.add_validator(moniker="cat") + env.add_validator(moniker="dog") + assert len(env.node_info) == 4 + env.start() + assert_validators_working(env) + # env._sifnoded_for(env.node_info[0]).wait_for_block(15) def test_add_validator_before_and_after_start(self): env = environments.SifnodedEnvironment(self.cmd, sifnoded_home_root=self.sifnoded_home_root) + assert len(env.node_info) == 0 env.add_validator() env.add_validator() + assert len(env.node_info) == 2 env.init() env.start() env.add_validator() - assert_validators_working(env, set("sifnoded-{}".format(i) for i in range(3))) + assert len(env.node_info) == 3 + assert_validators_working(env) def test_environment_fails_to_start_if_commission_rate_is_over_max(self): env = environments.SifnodedEnvironment(self.cmd, sifnoded_home_root=self.sifnoded_home_root) From 71dee15f483b66b166965f19054204aea0523cd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jure=20=C5=BDvikart?= <7929905+jzvikart@users.noreply.github.com> Date: Mon, 9 Oct 2023 08:55:42 +0200 Subject: [PATCH 2/8] Support for creating testnet-2 --- .../framework/src/siftool/chainbuilder.py | 36 +++++++++++ .../framework/src/siftool/cosmos.py | 1 + .../framework/src/siftool/environments.py | 59 +++++++++++++------ .../framework/src/siftool/installers.py | 5 -- .../framework/src/siftool/sifchain.py | 4 +- .../framework/test/test_environments.py | 3 +- .../framework/test/test_sifnoded.py | 2 +- 7 files changed, 82 insertions(+), 28 deletions(-) create mode 100644 test/integration/framework/src/siftool/chainbuilder.py delete mode 100644 test/integration/framework/src/siftool/installers.py diff --git a/test/integration/framework/src/siftool/chainbuilder.py b/test/integration/framework/src/siftool/chainbuilder.py new file mode 100644 index 0000000000..c24eaa76aa --- /dev/null +++ b/test/integration/framework/src/siftool/chainbuilder.py @@ -0,0 +1,36 @@ +import sys + +from siftool import common, command, environments, project + + +def __brutally_terminate_processes(cmd): + prj = project.Project(cmd, common.project_dir()) + prj.pkill() + + +def install_testnet(cmd: command.Command, base_dir: str, chain_id: str): + # mnemonics = { + # "sif": "race draft rival universe maid cheese steel logic crowd fork comic easy truth drift tomorrow eye buddy head time cash swing swift midnight borrow", + # "akasha": "hand inmate canvas head lunar naive increase recycle dog ecology inhale december wide bubble hockey dice worth gravity ketchup feed balance parent secret orchard", + # "juniper": "clump genre baby drum canvas uncover firm liberty verb moment access draft erupt fog alter gadget elder elephant divide biology choice sentence oppose avoid", + # "ethereum_root": "candy maple cake sugar pudding cream honey rich smooth crumble sweet treat", + # } + env = environments.SifnodedEnvironment(cmd, chain_id=chain_id, sifnoded_home_root=base_dir) + env.add_validator(moniker="ant") + env.add_validator(moniker="bee", pruning="nothing") + env.add_validator(moniker="cat", pruning="everything") + env.add_validator(moniker="dog", pruning="everything") + env.start() + env._client_for().wait_for_block(15) + __brutally_terminate_processes(cmd) + + +def main(*argv): + cmd = command.Command() + base_dir = argv[0] + chain_id = argv[1] + install_testnet(cmd, base_dir, chain_id) + + +if __name__ == "__main__": + main(*sys.argv) diff --git a/test/integration/framework/src/siftool/cosmos.py b/test/integration/framework/src/siftool/cosmos.py index dd853f093d..f3dc075b0d 100644 --- a/test/integration/framework/src/siftool/cosmos.py +++ b/test/integration/framework/src/siftool/cosmos.py @@ -8,6 +8,7 @@ Balance = Mapping[str, int] CompatBalance = Union[LegacyBalance, Balance] Address = str +AccountName = str Bank = Mapping[Address, Balance] BechAddress = str KeyName = str # Name of key in the keyring diff --git a/test/integration/framework/src/siftool/environments.py b/test/integration/framework/src/siftool/environments.py index 579a76c54f..44caa76d2a 100644 --- a/test/integration/framework/src/siftool/environments.py +++ b/test/integration/framework/src/siftool/environments.py @@ -1,3 +1,4 @@ +import json from typing import Tuple from siftool.common import * from siftool.sifchain import ROWAN, ROWAN_DECIMALS, STAKE @@ -5,7 +6,7 @@ # Environment for load test test_many_pools_and_liquidity_providers and for testing min commission/max voting power -# Supports multiple sifnoded validatos, no Ethereum support yet +# Supports multiple sifnoded validators, no Ethereum support yet # # class SifnodedEnvironment: @@ -18,6 +19,8 @@ def __init__(self, cmd: command.Command, chain_id: Optional[str] = None, sifnode self.default_binary = "sifnoded" self.node_info: List[JsonDict] = [] self.clp_admin: Optional[cosmos.Address] = None + self.oracle_admin: Optional[cosmos.Address] = None + self.whitelister_admin: Optional[cosmos.Address] = None self.faucet: Optional[cosmos.Address] = None self.running_processes = [] self.open_log_files = [] @@ -26,12 +29,12 @@ def __init__(self, cmd: command.Command, chain_id: Optional[str] = None, sifnode def add_validator(self, /, binary: Optional[str] = None, admin_name: Optional[str] = None, admin_mnemonic: Optional[Sequence[str]] = None, moniker: Optional[str] = None, home: Optional[str] = None, - staking_amount: Optional[int] = None, initial_balance: Optional[cosmos.Balance] = None, - commission_rate: Optional[float] = None, commission_max_rate: Optional[float] = None, - commission_max_change_rate: Optional[float] = None, min_self_delegation: Optional[int] = None, - ports: Mapping[str, int] = None, pruning: Optional[str] = None, pruning_keep_recent: Optional[int] = None, - pruning_keep_every: Optional[int] = None, pruning_interval: Optional[int] = None, - log_level: Optional[str] = None, log_file: Optional[str] = None + external_host: Optional[str] = None, external_port: Optional[int] = None, staking_amount: Optional[int] = None, + initial_balance: Optional[cosmos.Balance] = None, commission_rate: Optional[float] = None, + commission_max_rate: Optional[float] = None, commission_max_change_rate: Optional[float] = None, + min_self_delegation: Optional[int] = None, ports: Mapping[str, int] = None, pruning: Optional[str] = None, + pruning_keep_recent: Optional[int] = None, pruning_keep_every: Optional[int] = None, + pruning_interval: Optional[int] = None, log_level: Optional[str] = None, log_file: Optional[str] = None ): next_id = len(self.node_info) @@ -48,12 +51,15 @@ def add_validator(self, /, binary: Optional[str] = None, admin_name: Optional[s ports = ports if ports else self.ports_for_node(next_id) log_level = log_level if log_level is not None else "debug" log_file = log_file if log_file is not None else os.path.join(home, "sifnoded.log") + external_host = external_host if external_host is not None else LOCALHOST + external_port = external_port if external_port is not None else ports["rpc"] node_info = { "binary": binary, "moniker": moniker, "home": home, - "host": LOCALHOST, + "external_host": external_host, + "external_port": external_port, "admin_name": admin_name, "staking_amount": staking_amount, "initial_balance": initial_balance, @@ -108,7 +114,9 @@ def ports_for_node(self, i: int) -> JsonDict: } def init(self, faucet_balance: Optional[cosmos.Balance] = None, extra_accounts: Optional[cosmos.Bank] = None, - min_deposit: Optional[int] = None + min_deposit: Optional[int] = None, genesis_clp_admin: Optional[cosmos.Address] = None, + genesis_oracle_admin: Optional[cosmos.Address] = None, + genesis_whitelister_admin: Optional[cosmos.Address] = None ): # We must have at least one validator defined. The fist validator will be the default (i.e. it will be a peer # for all others, it will be used as the source of genesis file, it will host the faucet account) @@ -130,11 +138,13 @@ def init(self, faucet_balance: Optional[cosmos.Balance] = None, extra_accounts: sifnoded0.add_genesis_validators(admin_bech) admin0_addr = node_info0["admin_addr"] - admin0_name = node_info0["admin_name"] - self.clp_admin = admin0_addr - sifnoded0.add_genesis_clp_admin(admin0_addr) - sifnoded0.set_genesis_oracle_admin(admin0_name) - sifnoded0.set_genesis_whitelister_admin(admin0_name) + # admin0_name = node_info0["admin_name"] + self.clp_admin = genesis_clp_admin or admin0_addr + self.oracle_admin = genesis_oracle_admin or admin0_addr + self.whitelister_admin = genesis_whitelister_admin or admin0_addr + sifnoded0.add_genesis_clp_admin(self.clp_admin) + sifnoded0.set_genesis_oracle_admin(self.oracle_admin) + sifnoded0.set_genesis_whitelister_admin(self.whitelister_admin) extra_genesis_balances = cosmos.balance_sum_by_address({self.faucet: faucet_balance}, extra_accounts if extra_accounts is not None else {}) @@ -197,9 +207,10 @@ def start(self): self._broadcast_create_validator_msg(node_info) self.sifnoded = sifchain.Sifnoded(self.cmd, home=self.keyring_dir, chain_id=self.chain_id, - node=sifchain.format_node_url(self.node_info[0]["host"], self.node_info[0]["ports"]["rpc"]), + node=sifchain.format_node_url(self.node_info[0]["external_host"], self.node_info[0]["external_port"]), binary=self.node_info[0]["binary"]) + self.cmd.write_text_file(os.path.join(self.sifnoded_home_root, "summary.json"), json.dumps(self._get_summary_dict(), indent=4)) self._state = 2 def fund(self, address: cosmos.Address, amounts: cosmos.Balance): @@ -247,7 +258,7 @@ def upgrade(self, new_version: str, new_binary: str, upgrade_height: int, deposi assert sifnoded.version() == new_version self.sifnoded = sifchain.Sifnoded(self.cmd, home=self.keyring_dir, chain_id=self.chain_id, - node=sifchain.format_node_url(self.node_info[0]["host"], self.node_info[0]["ports"]["rpc"]), + node=sifchain.format_node_url(self.node_info[0]["external_host"], self.node_info[0]["external_port"]), binary = self.node_info[0]["binary"]) # Adjust configuration files for i != 0node. @@ -274,7 +285,7 @@ def _update_configuration_files(self, node_info, peers_node_info): app_toml["grpc-web"]["address"] = "{}:{}".format(ANY_ADDR, node_info["ports"]["grpc_web"]) # default "0.0.0.0:9091" config_toml["rpc"]["laddr"] = "tcp://{}:{}".format(ANY_ADDR, node_info["ports"]["rpc"]) # default "tcp://127.0.0.1:26657" config_toml["p2p"]["laddr"] = "{}:{}".format(ANY_ADDR, node_info["ports"]["p2p"]) # default "tcp://0.0.0.0:26656" - config_toml['p2p']["external_address"] = "{}:{}".format(node_info["host"], node_info["ports"]["p2p"]) + config_toml['p2p']["external_address"] = "{}:{}".format(node_info["external_host"], node_info["external_port"]) # host:port that is announced to peers if peers: config_toml["p2p"]["persistent_peers"] = ",".join(peers) config_toml['p2p']['max_num_inbound_peers'] = 50 @@ -286,6 +297,16 @@ def _update_configuration_files(self, node_info, peers_node_info): sifnoded.save_app_toml(app_toml) sifnoded.save_config_toml(config_toml) + def _get_summary_dict(self): + return { + "chain_id": self.chain_id, + "faucet": self.faucet, + "clp_admin": self.clp_admin, + "oracle_admin": self.oracle_admin, + "whitelister_admin": self.whitelister_admin, + "validators": self.node_info, + } + # This constructs a sifnoded CLI wrapper with values for --home, --chain_id and --node taken from corresponding # node_info. Typically you want a CLI wrapper associated with a single running validator, but in some cases such as # delegation or creating a new validator you want to use validator's own --home, but --node pointing to a @@ -294,13 +315,13 @@ def _sifnoded_for(self, node_info: JsonDict, to_node_info: Optional[JsonDict] = binary = node_info["binary"] home = node_info["home"] to_node_info = to_node_info if to_node_info is not None else node_info - node = sifchain.format_node_url(to_node_info["host"], to_node_info["ports"]["rpc"]) + node = sifchain.format_node_url(to_node_info["external_host"], to_node_info["external_port"]) return sifchain.Sifnoded(self.cmd, binary=binary, home=home, chain_id=self.chain_id, node=node) # Returns a Sifnoded that uses a default binary with the "keyring" profile and pointing to specific validator. def _client_for(self, node_index: int = 0) -> sifchain.Sifnoded: to_node_info = self.node_info[node_index] - node = sifchain.format_node_url(to_node_info["host"], to_node_info["ports"]["rpc"]) + node = sifchain.format_node_url(to_node_info["external_host"], to_node_info["external_port"]) return sifchain.Sifnoded(self.cmd, home=self.keyring_dir, chain_id=self.chain_id, node=node) def _sifnoded_start(self, node_info: JsonDict): diff --git a/test/integration/framework/src/siftool/installers.py b/test/integration/framework/src/siftool/installers.py deleted file mode 100644 index ac257bb103..0000000000 --- a/test/integration/framework/src/siftool/installers.py +++ /dev/null @@ -1,5 +0,0 @@ -from siftool.command import Command - -cmd = Command() - -print(repr(cmd)) diff --git a/test/integration/framework/src/siftool/sifchain.py b/test/integration/framework/src/siftool/sifchain.py index 7b50df7e53..f3ffe44ec1 100644 --- a/test/integration/framework/src/siftool/sifchain.py +++ b/test/integration/framework/src/siftool/sifchain.py @@ -372,13 +372,13 @@ def add_genesis_validators_peggy(self, evm_network_descriptor: int, valoper: cos self._home_args() self.sifnoded_exec(args) - def set_genesis_oracle_admin(self, address): + def set_genesis_oracle_admin(self, address: Union[cosmos.AccountName, cosmos.Address]): self.sifnoded_exec(["set-genesis-oracle-admin", address] + self._home_args() + self._keyring_backend_args()) def set_genesis_token_registry_admin(self, address): self.sifnoded_exec(["set-genesis-token-registry-admin", address] + self._home_args()) - def set_genesis_whitelister_admin(self, address): + def set_genesis_whitelister_admin(self, address: Union[cosmos.AccountName, cosmos.Address]): self.sifnoded_exec(["set-genesis-whitelister-admin", address] + self._home_args() + self._keyring_backend_args()) def set_gen_denom_whitelist(self, denom_whitelist_file): diff --git a/test/integration/framework/test/test_environments.py b/test/integration/framework/test/test_environments.py index c2e14bda0e..7b654addec 100644 --- a/test/integration/framework/test/test_environments.py +++ b/test/integration/framework/test/test_environments.py @@ -59,7 +59,8 @@ def test_environment_setup_basic_1(self): assert_validators_working(env) def test_environment_setup_basic_4(self): - env = environments.SifnodedEnvironment(self.cmd, chain_id="sifchain-testnet-2", sifnoded_home_root=self.sifnoded_home_root) + env = environments.SifnodedEnvironment(self.cmd, chain_id="cownet-2", sifnoded_home_root=self.sifnoded_home_root) + assert len(env.node_info) == 0 env.add_validator(moniker="ant") env.add_validator(moniker="bee") env.add_validator(moniker="cat") diff --git a/test/integration/framework/test/test_sifnoded.py b/test/integration/framework/test/test_sifnoded.py index d107b88e66..908168aded 100644 --- a/test/integration/framework/test/test_sifnoded.py +++ b/test/integration/framework/test/test_sifnoded.py @@ -38,7 +38,7 @@ def test_batching_and_paged_reads(self): clp_admin = validator0_admin sifnoded = sifchain.Sifnoded(self.cmd, home=tmpdir, chain_id=env.chain_id, - node=sifchain.format_node_url(env.node_info[0]["host"], env.node_info[0]["ports"]["rpc"])) + node=sifchain.format_node_url(env.node_info[0]["external_host"], env.node_info[0]["external_port"])) test_addr_actual_balance = sifnoded.get_balance(test_addr) assert test_addr_actual_balance == test_addr_balance From 667cd2fd816f94a1a324ff7174e8de176ff602bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jure=20=C5=BDvikart?= <7929905+jzvikart@users.noreply.github.com> Date: Tue, 10 Oct 2023 08:40:56 +0200 Subject: [PATCH 3/8] Support for non-validator nodes --- .../framework/resources/sifnoded.sh | 36 +++++++ .../framework/resources/sifnoded@.service | 16 ++++ .../framework/src/siftool/chainbuilder.py | 17 ++-- .../framework/src/siftool/environments.py | 94 +++++++++++-------- .../framework/src/siftool/sifchain.py | 2 +- .../framework/test/test_environments.py | 17 +++- 6 files changed, 130 insertions(+), 52 deletions(-) create mode 100644 test/integration/framework/resources/sifnoded.sh create mode 100644 test/integration/framework/resources/sifnoded@.service diff --git a/test/integration/framework/resources/sifnoded.sh b/test/integration/framework/resources/sifnoded.sh new file mode 100644 index 0000000000..ba1d852ff3 --- /dev/null +++ b/test/integration/framework/resources/sifnoded.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +set -euo pipefail + +BASEDIR="$0" +while [ -h "$BASEDIR" ]; do + ls=$(ls -ld "$BASEDIR") + link=$(expr "$ls" : '.*-> \(.*\)$') + if expr "$link" : '/.*' > /dev/null; then + BASEDIR="$link" + else + BASEDIR="$(dirname "$BASEDIR")/$link" + fi +done +BASEDIR="$(dirname "$BASEDIR")" +BASEDIR="$(cd "$BASEDIR"; pwd)" + +SERVICE_NAME="${1-}" + +if [ -z "$SERVICE_NAME" ]; then + echo "Mising parameter: SERVICE_NAME" + exit 255 +fi + +echo $BASEDIR +echo $SERVICE_NAME + +export DAEMON_NAME="sifnoded" +export DAEMON_HOME="$BASEDIR/$SERVICE_NAME" +export DAEMON_ALLOW_DOWNLOAD_BINARIES="true" +export DAEMON_RESTART_AFTER_UPGRADE="true" +export UNSAFE_SKIP_BACKUP="true" + +echo "Running cosmovisor for ${SERVICE_NAME} in ${DAEMON_HOME}..." + +"$BASEDIR/cosmovisor" start --home "${DAEMON_HOME}" diff --git a/test/integration/framework/resources/sifnoded@.service b/test/integration/framework/resources/sifnoded@.service new file mode 100644 index 0000000000..64d440128e --- /dev/null +++ b/test/integration/framework/resources/sifnoded@.service @@ -0,0 +1,16 @@ +[Unit] +Description="sifchain node %I" +After=network-online.target + +[Service] +User=sif +ExecStart=/home/sif/testnet/sifnode/sifnoded.sh %i +Restart=always +RestartSec=15 +LimitNOFILE=4096 +# SyslogIdentifier=sifnoded-%i +StandardOutput=append:/home/sif/testnet/sifnode/%i/sifnoded.log +StandardError=inherit + +[Install] +WantedBy=multi-user.target diff --git a/test/integration/framework/src/siftool/chainbuilder.py b/test/integration/framework/src/siftool/chainbuilder.py index c24eaa76aa..7a9afcc323 100644 --- a/test/integration/framework/src/siftool/chainbuilder.py +++ b/test/integration/framework/src/siftool/chainbuilder.py @@ -1,6 +1,6 @@ import sys -from siftool import common, command, environments, project +from siftool import common, command, environments, project, sifchain def __brutally_terminate_processes(cmd): @@ -15,13 +15,16 @@ def install_testnet(cmd: command.Command, base_dir: str, chain_id: str): # "juniper": "clump genre baby drum canvas uncover firm liberty verb moment access draft erupt fog alter gadget elder elephant divide biology choice sentence oppose avoid", # "ethereum_root": "candy maple cake sugar pudding cream honey rich smooth crumble sweet treat", # } + external_host = "147.135.105.196" env = environments.SifnodedEnvironment(cmd, chain_id=chain_id, sifnoded_home_root=base_dir) - env.add_validator(moniker="ant") - env.add_validator(moniker="bee", pruning="nothing") - env.add_validator(moniker="cat", pruning="everything") - env.add_validator(moniker="dog", pruning="everything") + env.add_validator(moniker="node-0", external_host=external_host, pruning="default") + env.add_validator(moniker="node-1", external_host=external_host, pruning="nothing") + env.add_validator(moniker="node-2", external_host=external_host, pruning="everything") + env.add_validator(moniker="node-3", external_host=external_host, pruning="everything") + env.init(faucet_balance={sifchain.ROWAN: 10**30, sifchain.STAKE: 10**30}) env.start() - env._client_for().wait_for_block(15) + sifnoded = env._client_for() + sifnoded.wait_for_block(sifnoded.get_current_block() + 10) __brutally_terminate_processes(cmd) @@ -33,4 +36,4 @@ def main(*argv): if __name__ == "__main__": - main(*sys.argv) + main(*sys.argv[1:]) diff --git a/test/integration/framework/src/siftool/environments.py b/test/integration/framework/src/siftool/environments.py index 44caa76d2a..b9566165f5 100644 --- a/test/integration/framework/src/siftool/environments.py +++ b/test/integration/framework/src/siftool/environments.py @@ -25,9 +25,10 @@ def __init__(self, cmd: command.Command, chain_id: Optional[str] = None, sifnode self.running_processes = [] self.open_log_files = [] self._state = 0 + self.sifnoded_connect_host = LOCALHOST # The hostname for building sifnoded '--node' argument self.sifnoded = sifchain.Sifnoded(self.cmd, home=self.keyring_dir, chain_id=self.chain_id) - def add_validator(self, /, binary: Optional[str] = None, admin_name: Optional[str] = None, + def add_validator(self, /, binary: Optional[str] = None, admin_name: Optional[str] = None, is_validator: bool = True, admin_mnemonic: Optional[Sequence[str]] = None, moniker: Optional[str] = None, home: Optional[str] = None, external_host: Optional[str] = None, external_port: Optional[int] = None, staking_amount: Optional[int] = None, initial_balance: Optional[cosmos.Balance] = None, commission_rate: Optional[float] = None, @@ -37,6 +38,7 @@ def add_validator(self, /, binary: Optional[str] = None, admin_name: Optional[s pruning_interval: Optional[int] = None, log_level: Optional[str] = None, log_file: Optional[str] = None ): next_id = len(self.node_info) + assert is_validator or (next_id > 0), "First node must be a validator" binary = binary if binary is not None else self.default_binary moniker = moniker if moniker is not None else "sifnoded-{}".format(next_id) @@ -60,6 +62,7 @@ def add_validator(self, /, binary: Optional[str] = None, admin_name: Optional[s "home": home, "external_host": external_host, "external_port": external_port, + "is_validator": is_validator, "admin_name": admin_name, "staking_amount": staking_amount, "initial_balance": initial_balance, @@ -68,21 +71,25 @@ def add_validator(self, /, binary: Optional[str] = None, admin_name: Optional[s "commission_max_change_rate": commission_max_change_rate, "min_self_delegation": min_self_delegation, "ports": ports, - "pruning": pruning, - "pruning_keep_recent": pruning_keep_recent, - "pruning_keep_every": pruning_keep_every, - "pruning_interval": pruning_interval, "log_level": log_level, "log_file": log_file, } if admin_mnemonic is not None: node_info["admin_mnemonic"] = admin_mnemonic + if pruning is not None: + node_info["pruning"] = pruning + if pruning_keep_recent is not None: + node_info["pruning_keep_recent"] = pruning_keep_recent + if pruning_keep_every is not None: + node_info["pruning_keep_every"] = pruning_keep_every + if pruning_interval is not None: + node_info["pruning_interval"] = pruning_interval next_index = len(self.node_info) is_first = next_index == 0 peers = [] if is_first else [self.node_info[0]] - self._create_validator_home(node_info) + self._create_sifnoded_home(node_info) self._update_configuration_files(node_info, peers) if self._state == 1: @@ -98,7 +105,8 @@ def add_validator(self, /, binary: Optional[str] = None, admin_name: Optional[s sifnoded_i = self._sifnoded_for(node_info) sifnoded_i.save_genesis_json(sifnoded.load_genesis_json()) self._sifnoded_start(node_info) - self._broadcast_create_validator_msg(node_info) + if is_validator: + self._broadcast_create_validator_msg(node_info) self.node_info.append(node_info) @@ -130,12 +138,13 @@ def init(self, faucet_balance: Optional[cosmos.Balance] = None, extra_accounts: sifnoded0 = self._sifnoded_for(node_info0) for node_info in self.node_info: - sifnoded = self._sifnoded_for(node_info) - admin_addr = node_info["admin_addr"] - admin_bech = sifnoded.get_val_address(admin_addr) - validator_balance = cosmos.balance_add({self.staking_denom: node_info["staking_amount"]}, node_info["initial_balance"]) - sifnoded0.add_genesis_account(admin_addr, validator_balance) - sifnoded0.add_genesis_validators(admin_bech) + if node_info["is_validator"]: + sifnoded = self._sifnoded_for(node_info) + admin_addr = node_info["admin_addr"] + admin_bech = sifnoded.get_val_address(admin_addr) + validator_balance = cosmos.balance_add({self.staking_denom: node_info["staking_amount"]}, node_info["initial_balance"]) + sifnoded0.add_genesis_account(admin_addr, validator_balance) + sifnoded0.add_genesis_validators(admin_bech) admin0_addr = node_info0["admin_addr"] # admin0_name = node_info0["admin_name"] @@ -204,7 +213,8 @@ def start(self): sifnoded0.wait_for_last_transaction_to_be_mined() for node_info in other_validators: - self._broadcast_create_validator_msg(node_info) + if node_info["is_validator"]: + self._broadcast_create_validator_msg(node_info) self.sifnoded = sifchain.Sifnoded(self.cmd, home=self.keyring_dir, chain_id=self.chain_id, node=sifchain.format_node_url(self.node_info[0]["external_host"], self.node_info[0]["external_port"]), @@ -271,13 +281,13 @@ def _update_configuration_files(self, node_info, peers_node_info): app_toml = sifnoded.load_app_toml() config_toml = sifnoded.load_config_toml() app_toml["minimum-gas-prices"] = sif_format_amount(0.5, ROWAN) - if node_info["pruning"] is not None: + if node_info.get("pruning", None) is not None: app_toml["pruning"] = node_info["pruning"] - if node_info["pruning_keep_recent"] is not None: + if node_info.get("pruning_keep_recent", None) is not None: app_toml["pruning-keep-recent"] = str(node_info["pruning_keep_recent"]) - if node_info["pruning_keep_every"] is not None: + if node_info.get("pruning_keep_every", None) is not None: app_toml["pruning-keep-every"] = str(node_info["pruning_keep_every"]) - if node_info["pruning_interval"] is not None: + if node_info.get("pruning_interval", None) is not None: app_toml["pruning-interval"] = str(node_info["pruning_interval"]) app_toml['api']['enable'] = True app_toml["api"]["address"] = sifchain.format_node_url(ANY_ADDR, node_info["ports"]["api"]) # default "tcp://0.0.0.0:1317" @@ -315,13 +325,13 @@ def _sifnoded_for(self, node_info: JsonDict, to_node_info: Optional[JsonDict] = binary = node_info["binary"] home = node_info["home"] to_node_info = to_node_info if to_node_info is not None else node_info - node = sifchain.format_node_url(to_node_info["external_host"], to_node_info["external_port"]) + node = sifchain.format_node_url(self.sifnoded_connect_host, to_node_info["external_port"]) return sifchain.Sifnoded(self.cmd, binary=binary, home=home, chain_id=self.chain_id, node=node) # Returns a Sifnoded that uses a default binary with the "keyring" profile and pointing to specific validator. def _client_for(self, node_index: int = 0) -> sifchain.Sifnoded: to_node_info = self.node_info[node_index] - node = sifchain.format_node_url(to_node_info["external_host"], to_node_info["external_port"]) + node = sifchain.format_node_url(self.sifnoded_connect_host, to_node_info["external_port"]) return sifchain.Sifnoded(self.cmd, home=self.keyring_dir, chain_id=self.chain_id, node=node) def _sifnoded_start(self, node_info: JsonDict): @@ -378,27 +388,31 @@ def _broadcast_create_validator_msg(self, node_info: JsonDict): assert float(new_validator["commission"]["commission_rates"]["max_rate"]) == commission_max_rate assert float(new_validator["commission"]["commission_rates"]["max_change_rate"]) == commission_max_change_rate - def _create_validator_home(self, node_info: JsonDict): - # Create admin account. We want this account both in validator's home and in self.keyring_dir: - # - it has to be in validator's home because "set-genesis-oracle-admin" requires it and there is no separate - # "--keyring-dir" CLI option. Otherwise, we would prefer all accounts to be separated from validator home. - # - because it is also in self.keyring_dir all admin names have to be unique. - admin_name = node_info["admin_name"] - admin_mnemonic = node_info.get("admin_mnemonic", None) - sifnoded = sifchain.Sifnoded(self.cmd, home=self.keyring_dir) - admin_acct, admin_mnemonic = sifnoded._keys_add(admin_name, mnemonic=admin_mnemonic) # Creates if none given - admin_addr = admin_acct["address"] - node_info["admin_addr"] = admin_addr - - sifnoded_i = self._sifnoded_for(node_info) + def _create_sifnoded_home(self, node_info: JsonDict): + is_validator = node_info["is_validator"] moniker = node_info["moniker"] - sifnoded_i.init(moniker) - admin_account_copy = sifnoded_i.keys_add(admin_name, mnemonic=admin_mnemonic) - assert admin_account_copy["address"] == admin_addr - node_id = sifnoded_i.tendermint_show_node_id() # Taken from ${sifnoded_home}/config/node_key.json - pubkey = sifnoded_i.tendermint_show_validator() # Taken from ${sifnoded_home}/config/priv_validator_key.json - node_info["node_id"] = node_id - node_info["pubkey"] = pubkey + sifnoded_i = self._sifnoded_for(node_info) + + if is_validator: + # Create admin account. We want this account both in validator's home and in self.keyring_dir: + # - it has to be in validator's home because "set-genesis-oracle-admin" requires it and there is no separate + # "--keyring-dir" CLI option. Otherwise, we would prefer all accounts to be separated from validator home. + # - because it is also in self.keyring_dir all admin names have to be unique. + admin_name = node_info["admin_name"] + admin_mnemonic = node_info.get("admin_mnemonic", None) + sifnoded_client = sifchain.Sifnoded(self.cmd, home=self.keyring_dir) + admin_acct, admin_mnemonic = sifnoded_client._keys_add(admin_name, mnemonic=admin_mnemonic) # Creates if none given + admin_addr = admin_acct["address"] + sifnoded_i.init(moniker) + admin_account_copy = sifnoded_i.keys_add(admin_name, mnemonic=admin_mnemonic) + assert admin_account_copy["address"] == admin_addr + node_id = sifnoded_i.tendermint_show_node_id() # Taken from ${sifnoded_home}/config/node_key.json + pubkey = sifnoded_i.tendermint_show_validator() # Taken from ${sifnoded_home}/config/priv_validator_key.json + node_info["admin_addr"] = admin_addr + node_info["node_id"] = node_id + node_info["pubkey"] = pubkey + else: + sifnoded_i.init(moniker) def close(self): for p in self.running_processes: diff --git a/test/integration/framework/src/siftool/sifchain.py b/test/integration/framework/src/siftool/sifchain.py index f3ffe44ec1..9bd8a32c51 100644 --- a/test/integration/framework/src/siftool/sifchain.py +++ b/test/integration/framework/src/siftool/sifchain.py @@ -1092,7 +1092,7 @@ def _rpc_get(self, host, port, relative_url): log.debug("Result for {}: {} bytes".format(url, len(http_result_payload))) return json.loads(http_result_payload.decode("UTF-8")) - def wait_for_last_transaction_to_be_mined(self, count: int = 1, disable_log: bool = True, timeout: int = 90): + def wait_for_last_transaction_to_be_mined(self, count: int = 1, timeout: int = 90): log.debug("Waiting for last sifnode transaction to be mined...") start_time = time.time() initial_block = self.get_current_block() diff --git a/test/integration/framework/test/test_environments.py b/test/integration/framework/test/test_environments.py index 7b654addec..c19bcddb6d 100644 --- a/test/integration/framework/test/test_environments.py +++ b/test/integration/framework/test/test_environments.py @@ -13,7 +13,7 @@ def test_transfer(env): def assert_validators_working(env): - expected_monikers = [node_info["moniker"] for node_info in env.node_info] + expected_monikers = [node_info["moniker"] for node_info in env.node_info if node_info["is_validator"]] assert set(get_validators(env)) == set(expected_monikers) number_of_nodes = len(env.node_info) for i in range(number_of_nodes): @@ -52,13 +52,13 @@ def teardown_method(self): prj = project.Project(self.cmd, project_dir()) prj.pkill() - def test_environment_setup_basic_1(self): + def test_environment_setup_basic_1_validator(self): env = environments.SifnodedEnvironment(self.cmd, sifnoded_home_root=self.sifnoded_home_root) env.add_validator() env.start() assert_validators_working(env) - def test_environment_setup_basic_4(self): + def test_environment_setup_basic_4_validators(self): env = environments.SifnodedEnvironment(self.cmd, chain_id="cownet-2", sifnoded_home_root=self.sifnoded_home_root) assert len(env.node_info) == 0 env.add_validator(moniker="ant") @@ -68,7 +68,16 @@ def test_environment_setup_basic_4(self): assert len(env.node_info) == 4 env.start() assert_validators_working(env) - # env._sifnoded_for(env.node_info[0]).wait_for_block(15) + + def test_environment_setup_mix_of_nodes_and_validators(self): + env = environments.SifnodedEnvironment(self.cmd, chain_id="cownet-2", sifnoded_home_root=self.sifnoded_home_root) + assert len(env.node_info) == 0 + env.add_validator(moniker="ant", is_validator=True) + env.add_validator(moniker="bee", is_validator=False) + env.add_validator(moniker="cat", is_validator=True) + assert len(env.node_info) == 3 + env.start() + assert_validators_working(env) def test_add_validator_before_and_after_start(self): env = environments.SifnodedEnvironment(self.cmd, sifnoded_home_root=self.sifnoded_home_root) From 66d163a48cc6965832924bcea60035133d7f8144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jure=20=C5=BDvikart?= <7929905+jzvikart@users.noreply.github.com> Date: Wed, 11 Oct 2023 08:48:52 +0200 Subject: [PATCH 4/8] Scripts for testnet-2 --- .../framework/resources/sifnoded.sh | 36 ------------------- .../framework/resources/sifnoded@.service | 16 --------- .../framework/src/siftool/chainbuilder.py | 21 ++++++----- .../framework/src/siftool/environments.py | 8 ++--- 4 files changed, 14 insertions(+), 67 deletions(-) delete mode 100644 test/integration/framework/resources/sifnoded.sh delete mode 100644 test/integration/framework/resources/sifnoded@.service diff --git a/test/integration/framework/resources/sifnoded.sh b/test/integration/framework/resources/sifnoded.sh deleted file mode 100644 index ba1d852ff3..0000000000 --- a/test/integration/framework/resources/sifnoded.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -BASEDIR="$0" -while [ -h "$BASEDIR" ]; do - ls=$(ls -ld "$BASEDIR") - link=$(expr "$ls" : '.*-> \(.*\)$') - if expr "$link" : '/.*' > /dev/null; then - BASEDIR="$link" - else - BASEDIR="$(dirname "$BASEDIR")/$link" - fi -done -BASEDIR="$(dirname "$BASEDIR")" -BASEDIR="$(cd "$BASEDIR"; pwd)" - -SERVICE_NAME="${1-}" - -if [ -z "$SERVICE_NAME" ]; then - echo "Mising parameter: SERVICE_NAME" - exit 255 -fi - -echo $BASEDIR -echo $SERVICE_NAME - -export DAEMON_NAME="sifnoded" -export DAEMON_HOME="$BASEDIR/$SERVICE_NAME" -export DAEMON_ALLOW_DOWNLOAD_BINARIES="true" -export DAEMON_RESTART_AFTER_UPGRADE="true" -export UNSAFE_SKIP_BACKUP="true" - -echo "Running cosmovisor for ${SERVICE_NAME} in ${DAEMON_HOME}..." - -"$BASEDIR/cosmovisor" start --home "${DAEMON_HOME}" diff --git a/test/integration/framework/resources/sifnoded@.service b/test/integration/framework/resources/sifnoded@.service deleted file mode 100644 index 64d440128e..0000000000 --- a/test/integration/framework/resources/sifnoded@.service +++ /dev/null @@ -1,16 +0,0 @@ -[Unit] -Description="sifchain node %I" -After=network-online.target - -[Service] -User=sif -ExecStart=/home/sif/testnet/sifnode/sifnoded.sh %i -Restart=always -RestartSec=15 -LimitNOFILE=4096 -# SyslogIdentifier=sifnoded-%i -StandardOutput=append:/home/sif/testnet/sifnode/%i/sifnoded.log -StandardError=inherit - -[Install] -WantedBy=multi-user.target diff --git a/test/integration/framework/src/siftool/chainbuilder.py b/test/integration/framework/src/siftool/chainbuilder.py index 7a9afcc323..4b0df8b44f 100644 --- a/test/integration/framework/src/siftool/chainbuilder.py +++ b/test/integration/framework/src/siftool/chainbuilder.py @@ -9,19 +9,18 @@ def __brutally_terminate_processes(cmd): def install_testnet(cmd: command.Command, base_dir: str, chain_id: str): - # mnemonics = { - # "sif": "race draft rival universe maid cheese steel logic crowd fork comic easy truth drift tomorrow eye buddy head time cash swing swift midnight borrow", - # "akasha": "hand inmate canvas head lunar naive increase recycle dog ecology inhale december wide bubble hockey dice worth gravity ketchup feed balance parent secret orchard", - # "juniper": "clump genre baby drum canvas uncover firm liberty verb moment access draft erupt fog alter gadget elder elephant divide biology choice sentence oppose avoid", - # "ethereum_root": "candy maple cake sugar pudding cream honey rich smooth crumble sweet treat", - # } + faucet_mnemonic = "fiction cousin fragile allow fruit slogan useless sting exile virus scale dress fatigue eight clay sort tape between cargo flag civil rude umbrella sing".split() + node0_admin_mnemonic = "frog skin business valve fish fat glory syrup chicken skin slow ensure sun luggage wild click into paper swamp car ecology infant thought squeeze".split() + node1_admin_mnemonic = "system faculty master promote among arrive dose zone cream fame barrel warm slice please creek puzzle boat excess rain lonely cupboard flame punch shed".split() + node2_admin_mnemonic = "box fix inmate zoo night model inject gesture inquiry slice treat curve reopen portion absent adjust toilet lyrics resist same goddess dad damage sort".split() + node3_admin_mnemonic = "hundred usual invite burger chat final collect acquire magnet repair upon venue initial ride street other tail vanish bicycle soap icon camp tragic material".split() external_host = "147.135.105.196" env = environments.SifnodedEnvironment(cmd, chain_id=chain_id, sifnoded_home_root=base_dir) - env.add_validator(moniker="node-0", external_host=external_host, pruning="default") - env.add_validator(moniker="node-1", external_host=external_host, pruning="nothing") - env.add_validator(moniker="node-2", external_host=external_host, pruning="everything") - env.add_validator(moniker="node-3", external_host=external_host, pruning="everything") - env.init(faucet_balance={sifchain.ROWAN: 10**30, sifchain.STAKE: 10**30}) + env.add_validator(moniker="node-0", admin_mnemonic=node0_admin_mnemonic, external_host=external_host, pruning="default") + env.add_validator(moniker="node-1", admin_mnemonic=node1_admin_mnemonic, external_host=external_host, pruning="nothing") + env.add_validator(moniker="node-2", admin_mnemonic=node2_admin_mnemonic, external_host=external_host, pruning="everything") + env.add_validator(moniker="node-3", admin_mnemonic=node3_admin_mnemonic, external_host=external_host, pruning="everything") + env.init(faucet_balance={sifchain.ROWAN: 10**30, sifchain.STAKE: 10**30}, faucet_mnemonic=faucet_mnemonic) env.start() sifnoded = env._client_for() sifnoded.wait_for_block(sifnoded.get_current_block() + 10) diff --git a/test/integration/framework/src/siftool/environments.py b/test/integration/framework/src/siftool/environments.py index b9566165f5..380cb4aa93 100644 --- a/test/integration/framework/src/siftool/environments.py +++ b/test/integration/framework/src/siftool/environments.py @@ -121,16 +121,16 @@ def ports_for_node(self, i: int) -> JsonDict: "pprof": 10606 + i, } - def init(self, faucet_balance: Optional[cosmos.Balance] = None, extra_accounts: Optional[cosmos.Bank] = None, - min_deposit: Optional[int] = None, genesis_clp_admin: Optional[cosmos.Address] = None, - genesis_oracle_admin: Optional[cosmos.Address] = None, + def init(self, faucet_balance: Optional[cosmos.Balance] = None, faucet_mnemonic: Optional[Sequence[str]] = None, + extra_accounts: Optional[cosmos.Bank] = None, min_deposit: Optional[int] = None, + genesis_clp_admin: Optional[cosmos.Address] = None, genesis_oracle_admin: Optional[cosmos.Address] = None, genesis_whitelister_admin: Optional[cosmos.Address] = None ): # We must have at least one validator defined. The fist validator will be the default (i.e. it will be a peer # for all others, it will be used as the source of genesis file, it will host the faucet account) assert self.node_info - self.faucet = self.sifnoded.create_addr("faucet") + self.faucet = self.sifnoded.create_addr("faucet", mnemonic=faucet_mnemonic) faucet_balance = faucet_balance if faucet_balance is not None else {ROWAN: 10**30, STAKE: 10**30} # Setup genesis on initial validator From 7df83b5698f94925a2ff8f0c93639ea77c708350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jure=20=C5=BDvikart?= <7929905+jzvikart@users.noreply.github.com> Date: Thu, 12 Oct 2023 11:29:04 +0200 Subject: [PATCH 5/8] Initial configuration for testnet --- test/integration/framework/src/siftool/chainbuilder.py | 10 +++++++++- test/integration/framework/src/siftool/environments.py | 2 +- test/integration/framework/src/siftool/sifchain.py | 6 +++--- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/test/integration/framework/src/siftool/chainbuilder.py b/test/integration/framework/src/siftool/chainbuilder.py index 4b0df8b44f..08c09b698b 100644 --- a/test/integration/framework/src/siftool/chainbuilder.py +++ b/test/integration/framework/src/siftool/chainbuilder.py @@ -15,14 +15,22 @@ def install_testnet(cmd: command.Command, base_dir: str, chain_id: str): node2_admin_mnemonic = "box fix inmate zoo night model inject gesture inquiry slice treat curve reopen portion absent adjust toilet lyrics resist same goddess dad damage sort".split() node3_admin_mnemonic = "hundred usual invite burger chat final collect acquire magnet repair upon venue initial ride street other tail vanish bicycle soap icon camp tragic material".split() external_host = "147.135.105.196" + extra_denoms = {"testtoken-{}".format(i): 10**30 for i in range(0)} # Caner: we don't want any dummy tokens on testnet env = environments.SifnodedEnvironment(cmd, chain_id=chain_id, sifnoded_home_root=base_dir) env.add_validator(moniker="node-0", admin_mnemonic=node0_admin_mnemonic, external_host=external_host, pruning="default") env.add_validator(moniker="node-1", admin_mnemonic=node1_admin_mnemonic, external_host=external_host, pruning="nothing") env.add_validator(moniker="node-2", admin_mnemonic=node2_admin_mnemonic, external_host=external_host, pruning="everything") env.add_validator(moniker="node-3", admin_mnemonic=node3_admin_mnemonic, external_host=external_host, pruning="everything") - env.init(faucet_balance={sifchain.ROWAN: 10**30, sifchain.STAKE: 10**30}, faucet_mnemonic=faucet_mnemonic) + env.init(faucet_balance={sifchain.ROWAN: 10**30, sifchain.STAKE: 10**30} | extra_denoms, faucet_mnemonic=faucet_mnemonic) env.start() sifnoded = env._client_for() + + # Initial configuration of token registry. The method `token_registry_register_batch` already checks the result. + # Compared to https://www.notion.so/sifchain/TestNet-2-7b3df383906c40cd8d4ded7bb5532252?pvs=4#dc261e1451df45e3b06cb0f99c9c692f + # our defaults are display_name = external_symbol = "ROWAN". + sifnoded.token_registry_register_batch(env.clp_admin, + tuple(sifnoded.create_tokenregistry_entry(denom, denom, 18) for denom in [sifchain.ROWAN, sifchain.STAKE])) + sifnoded.wait_for_block(sifnoded.get_current_block() + 10) __brutally_terminate_processes(cmd) diff --git a/test/integration/framework/src/siftool/environments.py b/test/integration/framework/src/siftool/environments.py index 380cb4aa93..e9e945c59d 100644 --- a/test/integration/framework/src/siftool/environments.py +++ b/test/integration/framework/src/siftool/environments.py @@ -113,10 +113,10 @@ def add_validator(self, /, binary: Optional[str] = None, admin_name: Optional[s def ports_for_node(self, i: int) -> JsonDict: assert i < 10, "Change port configuration for 10 or more nodes" return { + "rpc": 10286 + i, "api": 10131 + i, "grpc": 10909 + i, "grpc_web": 10919 + i, - "rpc": 10286 + i, "p2p": 10276 + i, "pprof": 10606 + i, } diff --git a/test/integration/framework/src/siftool/sifchain.py b/test/integration/framework/src/siftool/sifchain.py index 9bd8a32c51..6a406d69e2 100644 --- a/test/integration/framework/src/siftool/sifchain.py +++ b/test/integration/framework/src/siftool/sifchain.py @@ -441,7 +441,7 @@ def query_staking_validators(self) -> JsonObj: # See scripts/ibc/tokenregistration for more information and examples. # JSON file can be generated with "sifnoded q tokenregistry generate" def create_tokenregistry_entry(self, symbol: str, sifchain_symbol: str, decimals: int, - permissions: Iterable[str] = None + permissions: Iterable[str] = None, external_symbol: Optional[str] = None, display_name: Optional[str] = None ) -> TokenRegistryParams: permissions = permissions if permissions is not None else ["CLP", "IBCEXPORT", "IBCIMPORT"] upper_symbol = symbol.upper() # Like "USDT" @@ -452,11 +452,11 @@ def create_tokenregistry_entry(self, symbol: str, sifchain_symbol: str, decimals "path": "", "ibc_channel_id": "", "ibc_counterparty_channel_id": "", - "display_name": upper_symbol, + "display_name": display_name if display_name is not None else upper_symbol, "display_symbol": "", "network": "", "address": "", - "external_symbol": upper_symbol, + "external_symbol": external_symbol if external_symbol is not None else upper_symbol, "transfer_limit": "", "permissions": list(permissions), "unit_denom": "", From 196b28922c42c22c08c9dfffc278bd691038f744 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jure=20=C5=BDvikart?= <7929905+jzvikart@users.noreply.github.com> Date: Mon, 16 Oct 2023 19:38:52 +0200 Subject: [PATCH 6/8] Few things for testing IBC transfers --- .../framework/src/siftool/chainbuilder.py | 1 + .../framework/src/siftool/cosmos.py | 9 ++++ ...environments_experimental_ibc_transfers.py | 47 +++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 test/integration/framework/test/test_environments_experimental_ibc_transfers.py diff --git a/test/integration/framework/src/siftool/chainbuilder.py b/test/integration/framework/src/siftool/chainbuilder.py index 08c09b698b..b758d46a00 100644 --- a/test/integration/framework/src/siftool/chainbuilder.py +++ b/test/integration/framework/src/siftool/chainbuilder.py @@ -8,6 +8,7 @@ def __brutally_terminate_processes(cmd): prj.pkill() +# This is used for bulding sifchain-testnet-2 def install_testnet(cmd: command.Command, base_dir: str, chain_id: str): faucet_mnemonic = "fiction cousin fragile allow fruit slogan useless sting exile virus scale dress fatigue eight clay sort tape between cargo flag civil rude umbrella sing".split() node0_admin_mnemonic = "frog skin business valve fish fat glory syrup chicken skin slow ensure sun luggage wild click into paper swamp car ecology infant thought squeeze".split() diff --git a/test/integration/framework/src/siftool/cosmos.py b/test/integration/framework/src/siftool/cosmos.py index f3dc075b0d..f64ee39fda 100644 --- a/test/integration/framework/src/siftool/cosmos.py +++ b/test/integration/framework/src/siftool/cosmos.py @@ -138,3 +138,12 @@ def transfer(cmd, channel, address, amount, from_addr, chain_id, node, gas_price return res # + + +# Example: "channel-141", "uosmo" -> "ibc/14F9BC3E44B8A9C1BE1FB08980FAB87034C9905EF17CF2F5008FC085218811CC" +# See https://tutorials.cosmos.network/tutorials/6-ibc-dev/ +def derive_ibc_denom_hash(channel: str, denom: str) -> str: + port = "transfer" # Seems to be a constant for IBC token transfers + s = "{}/{}/{}".format(port, channel, denom) + import hashlib + return "ibc/{}".format(hashlib.sha256(s.encode("UTF-8")).digest().hex().upper()) diff --git a/test/integration/framework/test/test_environments_experimental_ibc_transfers.py b/test/integration/framework/test/test_environments_experimental_ibc_transfers.py new file mode 100644 index 0000000000..4d4dc3bf59 --- /dev/null +++ b/test/integration/framework/test/test_environments_experimental_ibc_transfers.py @@ -0,0 +1,47 @@ +from siftool.common import * +from siftool import command, environments, project + + +# The goal of this test is to setup an local environment for testing IBC transfers. +# We are trying to spin up single-node sifnoded validator + single-node axelard validator, and then setup and run +# and Osmosis relayer ("rly") to relay IBC tokens between the chains. +# In addition to sifnoded, axelard and rly must be in PATH. +# TODO Not working yet +class TestSifnodedEnvironmentWithIBCTransfers: + def setup_method(self): + self.cmd = command.Command() + self.sifnoded_home_root = self.cmd.tmpdir("siftool.tmp") + self.cmd.rmdir(self.sifnoded_home_root) + self.cmd.mkdir(self.sifnoded_home_root) + prj = project.Project(self.cmd, project_dir()) + prj.pkill() + + def teardown_method(self): + prj = project.Project(self.cmd, project_dir()) + prj.pkill() + + def test_ibc_setup_and_transfers(self): + env = environments.SifnodedEnvironment(self.cmd, sifnoded_home_root=self.sifnoded_home_root) + env.add_validator() + env.start() + + axelard = Axelard(home=os.path.join(env.sifnoded_home_root + "axelard")) + + +class Axelard: + def __init__(self, /, chain_id: Optional[str] = None, binary: Optional[str] = None, home: Optional[str] = None): + self.chain_id = chain_id or "axelar-localnet" + self.binary = binary or "axelard" + self.home = home + self.ports = None + + def start(self): + pass + # For generic Cosmos-based chain: + # - keys add + # - init + # - add-genesis-account ... + # - add-genesis-validator ... <--- no such command in axelard + # - gentx --home --keyring-backend test --chain-id + # - collect-gentxs --home + # - validate-genesis From 5ceb41cf7e4aa4a038a94b0f29cc893be1abeb72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jure=20=C5=BDvikart?= <7929905+jzvikart@users.noreply.github.com> Date: Fri, 27 Oct 2023 15:23:01 +0200 Subject: [PATCH 7/8] Minor changes --- .../framework/src/siftool/chainbuilder.py | 3 +++ test/integration/framework/src/siftool/cosmos.py | 3 ++- .../framework/src/siftool/environments.py | 13 +++++++------ .../integration/framework/src/siftool/project.py | 6 +++--- .../framework/src/siftool/sifchain.py | 16 +++++++++++++++- 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/test/integration/framework/src/siftool/chainbuilder.py b/test/integration/framework/src/siftool/chainbuilder.py index b758d46a00..f46c4d8342 100644 --- a/test/integration/framework/src/siftool/chainbuilder.py +++ b/test/integration/framework/src/siftool/chainbuilder.py @@ -10,6 +10,9 @@ def __brutally_terminate_processes(cmd): # This is used for bulding sifchain-testnet-2 def install_testnet(cmd: command.Command, base_dir: str, chain_id: str): + prj = project.Project(cmd) + mnemonics = prj.read_peruser_config_file("mnemonics.json") + faucet_mnemonic = "fiction cousin fragile allow fruit slogan useless sting exile virus scale dress fatigue eight clay sort tape between cargo flag civil rude umbrella sing".split() node0_admin_mnemonic = "frog skin business valve fish fat glory syrup chicken skin slow ensure sun luggage wild click into paper swamp car ecology infant thought squeeze".split() node1_admin_mnemonic = "system faculty master promote among arrive dose zone cream fame barrel warm slice please creek puzzle boat excess rain lonely cupboard flame punch shed".split() diff --git a/test/integration/framework/src/siftool/cosmos.py b/test/integration/framework/src/siftool/cosmos.py index f64ee39fda..036e147822 100644 --- a/test/integration/framework/src/siftool/cosmos.py +++ b/test/integration/framework/src/siftool/cosmos.py @@ -133,7 +133,7 @@ def transfer(cmd, channel, address, amount, from_addr, chain_id, node, gas_price args = [akash_binary, "tx", "ibc-transfer", "transfer", "transfer", channel, address, amount, "--from", from_addr, "--keyring-backend", keyring_backend, "--chain-id", chain_id, "--node", node, "-y", "--gas-prices", gas_prices, - "--gas", gas, "--packet-timeout-timestam[", str(packet_timeout_timestamp)] + "--gas", gas, "--packet-timeout-timestamp", str(packet_timeout_timestamp)] res = cmd.execst(args) return res @@ -141,6 +141,7 @@ def transfer(cmd, channel, address, amount, from_addr, chain_id, node, gas_price # Example: "channel-141", "uosmo" -> "ibc/14F9BC3E44B8A9C1BE1FB08980FAB87034C9905EF17CF2F5008FC085218811CC" +# The channel_id is for the side that is receiving the denom (not the counterparty). # See https://tutorials.cosmos.network/tutorials/6-ibc-dev/ def derive_ibc_denom_hash(channel: str, denom: str) -> str: port = "transfer" # Seems to be a constant for IBC token transfers diff --git a/test/integration/framework/src/siftool/environments.py b/test/integration/framework/src/siftool/environments.py index e9e945c59d..df33ca9d4e 100644 --- a/test/integration/framework/src/siftool/environments.py +++ b/test/integration/framework/src/siftool/environments.py @@ -17,6 +17,7 @@ def __init__(self, cmd: command.Command, chain_id: Optional[str] = None, sifnode self.chain_id = chain_id or "localnet" self.staking_denom = ROWAN self.default_binary = "sifnoded" + self.port_offset = 0 self.node_info: List[JsonDict] = [] self.clp_admin: Optional[cosmos.Address] = None self.oracle_admin: Optional[cosmos.Address] = None @@ -113,12 +114,12 @@ def add_validator(self, /, binary: Optional[str] = None, admin_name: Optional[s def ports_for_node(self, i: int) -> JsonDict: assert i < 10, "Change port configuration for 10 or more nodes" return { - "rpc": 10286 + i, - "api": 10131 + i, - "grpc": 10909 + i, - "grpc_web": 10919 + i, - "p2p": 10276 + i, - "pprof": 10606 + i, + "rpc": 10286 + self.port_offset + i, + "api": 10131 + self.port_offset + i, + "grpc": 10909 + self.port_offset + i, + "grpc_web": 10919 + self.port_offset + i, + "p2p": 10276 + self.port_offset + i, + "pprof": 10606 + self.port_offset + i, } def init(self, faucet_balance: Optional[cosmos.Balance] = None, faucet_mnemonic: Optional[Sequence[str]] = None, diff --git a/test/integration/framework/src/siftool/project.py b/test/integration/framework/src/siftool/project.py index d4ee2026d0..b71738b518 100644 --- a/test/integration/framework/src/siftool/project.py +++ b/test/integration/framework/src/siftool/project.py @@ -168,14 +168,14 @@ def write_vagrantenv_sh(self, state_vars, data_dir, ethereum_websocket_address, self.cmd.write_text_file(vagrantenv_path, joinlines(format_as_shell_env_vars(env))) self.cmd.write_text_file(project_dir("test/integration/vagrantenv.json"), json.dumps(env)) - def get_peruser_config_dir(self): + def get_peruser_config_dir(self) -> str: return self.cmd.get_user_home(".config", "siftool") - def get_user_env_vars(self): + def get_user_env_vars(self) -> JsonDict: env_file = os.environ["SIFTOOL_ENV_FILE"] return json.loads(self.cmd.read_text_file(env_file)) - def read_peruser_config_file(self, name): + def read_peruser_config_file(self, name) -> Optional[JsonDict]: path = os.path.join(self.get_peruser_config_dir(), name + ".json") if self.cmd.exists(path): return json.loads(self.cmd.read_text_file(path)) diff --git a/test/integration/framework/src/siftool/sifchain.py b/test/integration/framework/src/siftool/sifchain.py index 6a406d69e2..0c1cee52bc 100644 --- a/test/integration/framework/src/siftool/sifchain.py +++ b/test/integration/framework/src/siftool/sifchain.py @@ -6,7 +6,7 @@ import re import toml import web3 # TODO Remove dependency -from typing import Mapping, Any, Tuple, AnyStr +from typing import Mapping, Any, Tuple from siftool import command, cosmos, eth from siftool.common import * @@ -1022,6 +1022,20 @@ def version(self) -> str: def gov_submit_software_upgrade(self, version: str, from_acct: cosmos.Address, deposit: cosmos.Balance, upgrade_height: int, upgrade_info: str, title: str, description: str, broadcast_mode: Optional[str] = None ): + # Example: + # sifnoded tx gov submit-proposal software-upgrade 1.2.0-beta \ + # --title "Sifchain 1.2.0-beta Upgrade" \ + # --description "Sifchain 1.2.0-beta Upgrade" \ + # --upgrade-height BLOCK_HEIGHT \ + # --deposit 50000000000000000000000rowan \ + # --from ACCOUNT \ + # --keyring-backend test \ + # --chain-id=sifchain-1 \ + # --node https://sifchain-rpc.polkachu.com:443 \ + # --broadcast-mode block \ + # --fees 10000000000000000000000rowan \ + # --gas 200000 \ + # --yes args = ["tx", "gov", "submit-proposal", "software-upgrade", version, "--from", from_acct, "--deposit", cosmos.balance_format(deposit), "--upgrade-height", str(upgrade_height), "--upgrade-info", upgrade_info, "--title", title, "--description", description] + self._home_args() + self._keyring_backend_args() + \ From 4d26aa0cee2cc6e7524e4a31bbbd0f7de7e2d72c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jure=20=C5=BDvikart?= <7929905+jzvikart@users.noreply.github.com> Date: Wed, 15 Nov 2023 15:07:16 +0100 Subject: [PATCH 8/8] Cleanup --- .../framework/src/siftool/chainbuilder.py | 18 ++++++++---------- .../framework/src/siftool/project.py | 4 ++++ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/test/integration/framework/src/siftool/chainbuilder.py b/test/integration/framework/src/siftool/chainbuilder.py index f46c4d8342..881e77c5c9 100644 --- a/test/integration/framework/src/siftool/chainbuilder.py +++ b/test/integration/framework/src/siftool/chainbuilder.py @@ -4,20 +4,18 @@ def __brutally_terminate_processes(cmd): - prj = project.Project(cmd, common.project_dir()) - prj.pkill() + project.get_project().pkill() # This is used for bulding sifchain-testnet-2 def install_testnet(cmd: command.Command, base_dir: str, chain_id: str): - prj = project.Project(cmd) - mnemonics = prj.read_peruser_config_file("mnemonics.json") - - faucet_mnemonic = "fiction cousin fragile allow fruit slogan useless sting exile virus scale dress fatigue eight clay sort tape between cargo flag civil rude umbrella sing".split() - node0_admin_mnemonic = "frog skin business valve fish fat glory syrup chicken skin slow ensure sun luggage wild click into paper swamp car ecology infant thought squeeze".split() - node1_admin_mnemonic = "system faculty master promote among arrive dose zone cream fame barrel warm slice please creek puzzle boat excess rain lonely cupboard flame punch shed".split() - node2_admin_mnemonic = "box fix inmate zoo night model inject gesture inquiry slice treat curve reopen portion absent adjust toilet lyrics resist same goddess dad damage sort".split() - node3_admin_mnemonic = "hundred usual invite burger chat final collect acquire magnet repair upon venue initial ride street other tail vanish bicycle soap icon camp tragic material".split() + prj = project.get_project(cmd) + mnemonics = prj.read_peruser_config_file("mnemonics") + faucet_mnemonic = mnemonics["sif1zk8wxg65k6702hu9lrxqqnf8vn74ykznf5e7hk"] + node0_admin_mnemonic = mnemonics["sif1kkfa9f2h933uj0u6dexcnucjen6m32vh0jlnq6"] + node1_admin_mnemonic = mnemonics["sif1q0ahne0jkuxf2lj52c35evt6kglsyqlcenwtuk"] + node2_admin_mnemonic = mnemonics["sif1m0dh2e4vyle6svxjukp7e688n340uzqprf4k77"] + node3_admin_mnemonic = mnemonics["sif1q3s9pxvxze0vwkwa34x3jukgumnaefnq24zs36"] external_host = "147.135.105.196" extra_denoms = {"testtoken-{}".format(i): 10**30 for i in range(0)} # Caner: we don't want any dummy tokens on testnet env = environments.SifnodedEnvironment(cmd, chain_id=chain_id, sifnoded_home_root=base_dir) diff --git a/test/integration/framework/src/siftool/project.py b/test/integration/framework/src/siftool/project.py index b71738b518..069babab1e 100644 --- a/test/integration/framework/src/siftool/project.py +++ b/test/integration/framework/src/siftool/project.py @@ -20,6 +20,10 @@ def killall(processes): p.wait() +def get_project(cmd: Command): + return Project(cmd, project_dir()) + + class Project: """Represents a checked out copy of a project in a particular directory."""