diff --git a/.changelog/unreleased/testing/3680-gen-localnet-fullnodes.md b/.changelog/unreleased/testing/3680-gen-localnet-fullnodes.md new file mode 100644 index 0000000000..9935207c52 --- /dev/null +++ b/.changelog/unreleased/testing/3680-gen-localnet-fullnodes.md @@ -0,0 +1,4 @@ +- Augment the functionality of `gen_localnet.py` with the ability + to generate full node base directories. Moreover, add a new script + to boot up a localnet with two genesis validators or a full node. + ([\#3680](https://github.com/anoma/namada/pull/3680)) \ No newline at end of file diff --git a/scripts/gen_localnet.py b/scripts/gen_localnet.py index e9323bec64..59896c2019 100755 --- a/scripts/gen_localnet.py +++ b/scripts/gen_localnet.py @@ -53,7 +53,7 @@ def main_inner(args, working_directory): f"Could not find {validator_alias} with addr {validator_addr} in {TRANSACTIONS_TEMPLATE}" ) - join_network( + join_network_with_validator( working_directory=working_directory, binaries=binaries, base_dir_prefix=base_dir_prefix, @@ -63,6 +63,18 @@ def main_inner(args, working_directory): command_summary=command_summary, ) + for fullnode_alias, full_node_base_port in args.full_nodes.items(): + join_network_with_fullnode( + working_directory=working_directory, + binaries=binaries, + base_dir_prefix=base_dir_prefix, + chain_id=chain_id, + fullnode_alias=fullnode_alias, + fullnode_base_port=full_node_base_port, + pre_genesis_path=args.pre_genesis_path, + command_summary=command_summary, + ) + info("Run the ledger(s) using the command string(s) below") for validator_alias, cmd_str in command_summary.items(): @@ -116,7 +128,7 @@ def init_network( return chain_id, templates -def join_network( +def join_network_with_validator( working_directory, binaries, base_dir_prefix, @@ -141,7 +153,7 @@ def join_network( base_dir = reset_base_dir( prefix=base_dir_prefix, - validator_alias=genesis_validator, + node_alias=genesis_validator, pre_genesis_wallet=pre_genesis_wallet_path, ) @@ -153,6 +165,7 @@ def join_network( base_dir, "utils", "join-network", + "--add-persistent-peers", "--allow-duplicate-ip", "--chain-id", chain_id, @@ -169,6 +182,72 @@ def join_network( ) +def join_network_with_fullnode( + working_directory, + binaries, + base_dir_prefix, + chain_id, + fullnode_alias, + fullnode_base_port, + pre_genesis_path, + command_summary, +): + info(f"Attempting to join {chain_id} with {fullnode_alias}") + + pre_genesis_wallet_path = pre_genesis_path / "wallet.toml" + + base_dir = reset_base_dir( + prefix=base_dir_prefix, + node_alias=fullnode_alias, + pre_genesis_wallet=pre_genesis_wallet_path, + ) + + system( + "env", + f"NAMADA_NETWORK_CONFIGS_DIR={working_directory}", + binaries[NAMADAC], + "--base-dir", + base_dir, + "utils", + "join-network", + "--add-persistent-peers", + "--allow-duplicate-ip", + "--chain-id", + chain_id, + ) + + update_fullnode_config( + full_node_base_port=fullnode_base_port, + fullnode_config_path=base_dir_prefix + / fullnode_alias + / chain_id + / "config.toml", + ) + + info(f"Full node {fullnode_alias} joined {chain_id}") + + command_summary[fullnode_alias] = ( + f"{binaries[NAMADA]} --base-dir='{base_dir}' ledger run" + ) + + +def update_fullnode_config(full_node_base_port, fullnode_config_path): + config = toml.load(fullnode_config_path) + + config["ledger"]["cometbft"]["rpc"][ + "laddr" + ] = f"tcp://127.0.0.1:{full_node_base_port}" + config["ledger"]["cometbft"][ + "proxy_app" + ] = f"tcp://127.0.0.1:{full_node_base_port + 1}" + config["ledger"]["cometbft"]["p2p"][ + "laddr" + ] = f"tcp://0.0.0.0:{full_node_base_port + 2}" + + with open(fullnode_config_path, "w") as output_file: + toml.dump(config, output_file) + + def log(color, descriptor, line): print(f"[{color}{Color.UNDERLINE}{descriptor}{Color.END}]: {line}") @@ -200,8 +279,8 @@ def parse_cli_args(): ) group = parser.add_argument_group( - title="Validator config", - description="Customize the validators the localnet will run with.", + title="Node config", + description="Customize the validators and full nodes the localnet will run with.", ) group.add_argument( "--templates", @@ -218,6 +297,12 @@ def parse_cli_args(): type=Path, help="Path to pre-genesis directory. Must be present with custom `--templates`.", ) + group.add_argument( + "--full-nodes", + default={}, + type=full_nodes_object, + help="JSON object of full node aliases to port numbers these will listen on.", + ) group = parser.add_argument_group( title="General config", @@ -321,6 +406,21 @@ def params_json_object(s): return params +def full_nodes_object(s): + full_nodes = json.loads(s) + + if type(full_nodes) != dict: + die("Only JSON objects allowed for full nodes") + + for value in full_nodes.values(): + if type(value) != int: + die( + "Only JSON objects with a mapping between full node aliases and base ports (range 0-65535) allowed" + ) + + return full_nodes + + def to_edit_from_args(args): if args.max_validator_slots: params = args.edit.setdefault(PARAMETERS_TEMPLATE, {}) @@ -448,8 +548,8 @@ def reset_base_dir_prefix(args): return prefix -def reset_base_dir(prefix, validator_alias, pre_genesis_wallet): - base_dir = prefix / validator_alias +def reset_base_dir(prefix, node_alias, pre_genesis_wallet): + base_dir = prefix / node_alias pre_genesis_dir = base_dir / "pre-genesis" os.mkdir(base_dir) os.mkdir(pre_genesis_dir) diff --git a/scripts/localnet-2.sh b/scripts/localnet-2.sh new file mode 100755 index 0000000000..5e4f5b2ded --- /dev/null +++ b/scripts/localnet-2.sh @@ -0,0 +1,77 @@ +#!/bin/sh + +set -e + +trap 'cleanup' EXIT INT TERM QUIT + +main() { + cd "$(dirname "$0")"/.. + _tmp="$(mktemp -d)" + + cp -r genesis/localnet "${_tmp}/" + + # import validator key and addr into the wallet + ./target/debug/namadaw \ + --pre-genesis \ + --base-dir "${_tmp}/localnet/src" \ + add \ + --unsafe-dont-encrypt \ + --alias validator-1-account-key \ + --value 00f1425456539dd53adbeda8c6d64b11c71c40c3d41fe17082a3dd89bc72cc26ae + ./target/debug/namadaw \ + --pre-genesis \ + --base-dir "${_tmp}/localnet/src" \ + add \ + --unsafe-dont-encrypt \ + --alias validator-1 \ + --value tnam1qyq850fy0tdk8wkp40hhwu8a9wp2wn8stq3ldqrg + + # create validator txs and sign them + ./target/debug/namadac \ + --pre-genesis \ + --base-dir "${_tmp}/localnet/src" \ + utils init-genesis-established-account \ + --aliases validator-1-account-key \ + --path "${_tmp}/unsigned.toml" + ./target/debug/namadac \ + --pre-genesis \ + --base-dir "${_tmp}/localnet/src" \ + utils init-genesis-validator \ + --path "${_tmp}/unsigned.toml" \ + --alias validator-1 \ + --address tnam1qyq850fy0tdk8wkp40hhwu8a9wp2wn8stq3ldqrg \ + --net-address 127.0.0.1:42042 \ + --commission-rate 0.10 \ + --max-commission-rate-change 0.01 \ + --unsafe-dont-encrypt \ + --self-bond-amount 100000 \ + --email bing@bong.us + ./target/debug/namadac \ + --pre-genesis \ + --base-dir "${_tmp}/localnet/src" \ + utils sign-genesis-txs \ + --path "${_tmp}/unsigned.toml" \ + --output "${_tmp}/signed.toml" \ + --alias validator-1 + cat "${_tmp}/signed.toml" >> "${_tmp}/localnet/transactions.toml" + + # attribute balance to new validator + sed \ + -i '' \ + 's/\(\[token\.BTC\]\)/tnam1qyq850fy0tdk8wkp40hhwu8a9wp2wn8stq3ldqrg = "200000"\ntnam1qr8l7l6rywucdarxg9q0zpggfe0jxddk6u09e8ez = "1000000"\n\1/' \ + "${_tmp}/localnet/balances.toml" + + # generate localnet + ./scripts/gen_localnet.py \ + --full-nodes '{"fullnode-0":12340}' \ + --templates "${_tmp}/localnet" \ + --validator-aliases '{"validator-0":"tnam1q9vhfdur7gadtwx4r223agpal0fvlqhywylf2mzx","validator-1":"tnam1qyq850fy0tdk8wkp40hhwu8a9wp2wn8stq3ldqrg"}' \ + --pre-genesis-path "${_tmp}/localnet/src/pre-genesis" \ + "$@" +} + +cleanup() { + rm -rf "$_tmp" +} + +main "$@"