diff --git a/.changelog/unreleased/improvements/3652-ctxless-node-utils.md b/.changelog/unreleased/improvements/3652-ctxless-node-utils.md new file mode 100644 index 0000000000..bd7a334d07 --- /dev/null +++ b/.changelog/unreleased/improvements/3652-ctxless-node-utils.md @@ -0,0 +1,2 @@ +- Do not load context for `namadan utils test-genesis` command. + ([\#3652](https://github.com/anoma/namada/pull/3652)) \ No newline at end of file diff --git a/.github/workflows/scripts/e2e.json b/.github/workflows/scripts/e2e.json index 5011893e3d..867edb432a 100644 --- a/.github/workflows/scripts/e2e.json +++ b/.github/workflows/scripts/e2e.json @@ -26,9 +26,10 @@ "e2e::ledger_tests::suspend_ledger": 30, "e2e::ledger_tests::stop_ledger_at_height": 18, "e2e::ledger_tests::change_consensus_key": 91, + "e2e::ledger_tests::test_localnet_genesis": 3, "e2e::wallet_tests::wallet_address_cmds": 1, "e2e::wallet_tests::wallet_encrypted_key_cmds": 1, "e2e::wallet_tests::wallet_encrypted_key_cmds_env_var": 1, "e2e::wallet_tests::wallet_unencrypted_key_cmds": 1, "e2e::ledger_tests::masp_txs_and_queries": 82 -} +} \ No newline at end of file diff --git a/crates/apps/src/bin/namada-node/cli.rs b/crates/apps/src/bin/namada-node/cli.rs index d0370b892b..52db0ee1a1 100644 --- a/crates/apps/src/bin/namada-node/cli.rs +++ b/crates/apps/src/bin/namada-node/cli.rs @@ -13,9 +13,9 @@ use namada_apps_lib::time::{DateTimeUtc, Utc}; use namada_node as node; pub fn main() -> Result<()> { - let (cmd, mut ctx) = cli::namada_node_cli()?; + let cmd = cli::namada_node_cli()?; match cmd { - cmds::NamadaNode::Ledger(sub) => match sub { + cli::NamadaNode::Ledger(cmd, ctx) => match cmd { cmds::Ledger::Run(cmds::LedgerRun(args)) => { let chain_ctx = ctx.take_chain_or_exit(); let wasm_dir = chain_ctx.wasm_dir(); @@ -110,7 +110,7 @@ pub fn main() -> Result<()> { ); } }, - cmds::NamadaNode::Config(sub) => match sub { + cli::NamadaNode::Config(cmd, mut ctx) => match cmd { cmds::Config::Gen(cmds::ConfigGen) => { // If the config doesn't exit, it gets generated in the context. // In here, we just need to overwrite the default chain ID, in @@ -166,7 +166,7 @@ pub fn main() -> Result<()> { std::fs::write(config_path, updated_config).unwrap(); } }, - cmds::NamadaNode::Utils(sub) => match sub { + cli::NamadaNode::Utils(sub, _global_args) => match sub { cmds::NodeUtils::TestGenesis(TestGenesis(args)) => { node::utils::test_genesis(args) } diff --git a/crates/apps_lib/src/cli.rs b/crates/apps_lib/src/cli.rs index b7deb07b81..92c0d33169 100644 --- a/crates/apps_lib/src/cli.rs +++ b/crates/apps_lib/src/cli.rs @@ -8333,14 +8333,44 @@ pub fn namada_cli() -> (cmds::Namada, String) { safe_exit(2); } -pub fn namada_node_cli() -> Result<(cmds::NamadaNode, Context)> { +/// Namada node commands with loaded [`Context`] where required +pub enum NamadaNode { + Ledger(cmds::Ledger, Context), + Config(cmds::Config, Context), + Utils(cmds::NodeUtils, args::Global), +} + +pub fn namada_node_cli() -> Result { let app = namada_node_app(); - cmds::NamadaNode::parse_or_print_help(app) + let matches = app.clone().get_matches(); + match Cmd::parse(&matches) { + Some(cmd) => { + let global_args = args::Global::parse(&matches); + match cmd { + cmds::NamadaNode::Ledger(sub_cmd) => { + let context = Context::new::(global_args)?; + Ok(NamadaNode::Ledger(sub_cmd, context)) + } + cmds::NamadaNode::Config(sub_cmd) => { + let context = Context::new::(global_args)?; + Ok(NamadaNode::Config(sub_cmd, context)) + } + cmds::NamadaNode::Utils(sub_cmd) => { + Ok(NamadaNode::Utils(sub_cmd, global_args)) + } + } + } + None => { + let mut app = app; + app.print_help().unwrap(); + safe_exit(2); + } + } } -#[allow(clippy::large_enum_variant)] +/// Namada client commands with loaded [`Context`] where required pub enum NamadaClient { - WithoutContext(cmds::ClientUtils, args::Global), + WithoutContext(Box<(cmds::ClientUtils, args::Global)>), WithContext(Box<(cmds::NamadaClientWithContext, Context)>), } @@ -8356,7 +8386,10 @@ pub fn namada_client_cli() -> Result { Ok(NamadaClient::WithContext(Box::new((sub_cmd, context)))) } cmds::NamadaClient::WithoutContext(sub_cmd) => { - Ok(NamadaClient::WithoutContext(sub_cmd, global_args)) + Ok(NamadaClient::WithoutContext(Box::new(( + sub_cmd, + global_args, + )))) } } } diff --git a/crates/apps_lib/src/cli/client.rs b/crates/apps_lib/src/cli/client.rs index 4a6d802b51..a7d66740ee 100644 --- a/crates/apps_lib/src/cli/client.rs +++ b/crates/apps_lib/src/cli/client.rs @@ -766,80 +766,89 @@ impl CliApi { } } } - cli::NamadaClient::WithoutContext(cmd, global_args) => match cmd { - // Utils cmds - ClientUtils::JoinNetwork(JoinNetwork(args)) => { - utils::join_network(global_args, args).await - } - ClientUtils::ValidateWasm(ValidateWasm(args)) => { - utils::validate_wasm(args) - } - ClientUtils::InitNetwork(InitNetwork(args)) => { - utils::init_network(global_args, args); - } - ClientUtils::GenesisBond(GenesisBond(args)) => { - utils::genesis_bond(global_args, args) - } - ClientUtils::DeriveGenesisAddresses( - DeriveGenesisAddresses(args), - ) => utils::derive_genesis_addresses(global_args, args), - ClientUtils::InitGenesisEstablishedAccount( - InitGenesisEstablishedAccount(args), - ) => utils::init_genesis_established_account(global_args, args), - ClientUtils::InitGenesisValidator(InitGenesisValidator( - args, - )) => utils::init_genesis_validator(global_args, args), - ClientUtils::PkToTmAddress(PkToTmAddress(args)) => { - utils::pk_to_tm_address(global_args, args) - } - ClientUtils::DefaultBaseDir(DefaultBaseDir(args)) => { - utils::default_base_dir(global_args, args) - } - ClientUtils::EpochSleep(EpochSleep(args)) => { - let mut ctx = cli::Context::new::(global_args) - .expect("expected to construct a context"); - let chain_ctx = ctx.borrow_mut_chain_or_exit(); - let ledger_address = chain_ctx.get(&args.ledger_address); - let client = C::from_tendermint_address(&ledger_address); - client.wait_until_node_is_synced(&io).await?; - let args = args.to_sdk(&mut ctx)?; - let namada = ctx.to_sdk(client, io); - rpc::epoch_sleep(&namada, args).await; - } - ClientUtils::ValidateGenesisTemplates( - ValidateGenesisTemplates(args), - ) => utils::validate_genesis_templates(global_args, args), - ClientUtils::SignGenesisTxs(SignGenesisTxs(args)) => { - utils::sign_genesis_tx(global_args, args).await - } - ClientUtils::ParseMigrationJson(MigrationJson(args)) => { - #[cfg(feature = "migrations")] - { - let mut update_json = String::new(); - let mut file = std::fs::File::open(args.path).expect( - "Could not fine updates file at the specified \ - path.", - ); - file.read_to_string(&mut update_json) - .expect("Unable to read the updates json file"); - let updates: namada_sdk::migrations::DbChanges = - serde_json::from_str(&update_json).expect( - "Could not parse the updates file as json", - ); - for change in updates.changes { - display_line!(io, "{}", change); - } + cli::NamadaClient::WithoutContext(cmd_box) => { + let (cmd, global_args) = *cmd_box; + match cmd { + // Utils cmds + ClientUtils::JoinNetwork(JoinNetwork(args)) => { + utils::join_network(global_args, args).await + } + ClientUtils::ValidateWasm(ValidateWasm(args)) => { + utils::validate_wasm(args) + } + ClientUtils::InitNetwork(InitNetwork(args)) => { + utils::init_network(global_args, args); + } + ClientUtils::GenesisBond(GenesisBond(args)) => { + utils::genesis_bond(global_args, args) + } + ClientUtils::DeriveGenesisAddresses( + DeriveGenesisAddresses(args), + ) => utils::derive_genesis_addresses(global_args, args), + ClientUtils::InitGenesisEstablishedAccount( + InitGenesisEstablishedAccount(args), + ) => utils::init_genesis_established_account( + global_args, + args, + ), + ClientUtils::InitGenesisValidator( + InitGenesisValidator(args), + ) => utils::init_genesis_validator(global_args, args), + ClientUtils::PkToTmAddress(PkToTmAddress(args)) => { + utils::pk_to_tm_address(global_args, args) } - #[cfg(not(feature = "migrations"))] - { - display_line!( - io, - "Can only use this function if compiled with \ - feature \"migrations\" enabled." - ) + ClientUtils::DefaultBaseDir(DefaultBaseDir(args)) => { + utils::default_base_dir(global_args, args) + } + ClientUtils::EpochSleep(EpochSleep(args)) => { + let mut ctx = cli::Context::new::(global_args) + .expect("expected to construct a context"); + let chain_ctx = ctx.borrow_mut_chain_or_exit(); + let ledger_address = + chain_ctx.get(&args.ledger_address); + let client = + C::from_tendermint_address(&ledger_address); + client.wait_until_node_is_synced(&io).await?; + let args = args.to_sdk(&mut ctx)?; + let namada = ctx.to_sdk(client, io); + rpc::epoch_sleep(&namada, args).await; + } + ClientUtils::ValidateGenesisTemplates( + ValidateGenesisTemplates(args), + ) => utils::validate_genesis_templates(global_args, args), + ClientUtils::SignGenesisTxs(SignGenesisTxs(args)) => { + utils::sign_genesis_tx(global_args, args).await + } + ClientUtils::ParseMigrationJson(MigrationJson(args)) => { + #[cfg(feature = "migrations")] + { + let mut update_json = String::new(); + let mut file = std::fs::File::open(args.path) + .expect( + "Could not fine updates file at the \ + specified path.", + ); + file.read_to_string(&mut update_json) + .expect("Unable to read the updates json file"); + let updates: namada_sdk::migrations::DbChanges = + serde_json::from_str(&update_json).expect( + "Could not parse the updates file as json", + ); + for change in updates.changes { + display_line!(io, "{}", change); + } + } + #[cfg(not(feature = "migrations"))] + { + display_line!( + io, + "Can only use this function if compiled with \ + feature \"migrations\" enabled." + ) + } } } - }, + } } Ok(()) } diff --git a/crates/node/src/lib.rs b/crates/node/src/lib.rs index ff756f5fa3..db33bdf666 100644 --- a/crates/node/src/lib.rs +++ b/crates/node/src/lib.rs @@ -958,8 +958,6 @@ pub fn test_genesis_files( // broadcaster service let (broadcast_sender, _broadcaster_receiver) = mpsc::unbounded_channel(); - // Start dummy broadcaster - let _broadcaster = spawn_dummy_task(()); let chain_id = config.chain_id.to_string(); // start an instance of the ledger let mut shell = Shell::::new( diff --git a/crates/node/src/shell/testing/client.rs b/crates/node/src/shell/testing/client.rs index f9921211ad..3222667684 100644 --- a/crates/node/src/shell/testing/client.rs +++ b/crates/node/src/shell/testing/client.rs @@ -44,7 +44,7 @@ pub fn run( NamadaClient::WithContext(Box::new((sub_cmd, ctx))) } cmds::NamadaClient::WithoutContext(sub_cmd) => { - NamadaClient::WithoutContext(sub_cmd, global) + NamadaClient::WithoutContext(Box::new((sub_cmd, global))) } }; rt.block_on(CliApi::handle_client_command( diff --git a/crates/tests/src/e2e/ledger_tests.rs b/crates/tests/src/e2e/ledger_tests.rs index 010d19ad4d..afe27d577e 100644 --- a/crates/tests/src/e2e/ledger_tests.rs +++ b/crates/tests/src/e2e/ledger_tests.rs @@ -20,9 +20,10 @@ use std::time::{Duration, Instant}; use color_eyre::eyre::Result; use color_eyre::owo_colors::OwoColorize; use namada_apps_lib::cli::context::ENV_VAR_CHAIN_ID; -use namada_apps_lib::config::ethereum_bridge; use namada_apps_lib::config::utils::convert_tm_addr_to_socket_addr; +use namada_apps_lib::config::{self, ethereum_bridge}; use namada_apps_lib::facade::tendermint_config::net::Address as TendermintAddress; +use namada_apps_lib::wallet; use namada_core::chain::ChainId; use namada_core::token::NATIVE_MAX_DECIMAL_PLACES; use namada_sdk::address::Address; @@ -2556,3 +2557,31 @@ fn masp_txs_and_queries() -> Result<()> { Ok(()) } + +/// Test localnet genesis files with `namada node utils test-genesis` command. +#[test] +fn test_localnet_genesis() -> Result<()> { + let loc = format!("{}:{}", std::file!(), std::line!()); + let dir = setup::TestDir::new(); + let working_dir = working_dir(); + let genesis_path = wallet::defaults::derive_template_dir(&working_dir); + let wasm_dir = working_dir.join(config::DEFAULT_WASM_DIR); + let mut test_genesis_result = setup::run_cmd( + Bin::Node, + [ + "utils", + "test-genesis", + "--path", + &genesis_path.to_string_lossy(), + "--wasm-dir", + &wasm_dir.to_string_lossy(), + ], + Some(30), + &working_dir, + dir.path(), + loc, + )?; + test_genesis_result + .exp_string("Genesis files were dry-run successfully")?; + Ok(()) +}