diff --git a/.changelog/unreleased/bug-fixes/1549-fix-init-validator-tm-mode.md b/.changelog/unreleased/bug-fixes/1549-fix-init-validator-tm-mode.md new file mode 100644 index 0000000000..33000a423d --- /dev/null +++ b/.changelog/unreleased/bug-fixes/1549-fix-init-validator-tm-mode.md @@ -0,0 +1,3 @@ +- PoS: Fixed the client to change configuration to validator + mode after a successful `init-validator` transaction. + ([\#1549](https://github.com/anoma/namada/pull/1549)) \ No newline at end of file diff --git a/apps/src/lib/client/tx.rs b/apps/src/lib/client/tx.rs index 235901e0b3..6bbf8a0ffa 100644 --- a/apps/src/lib/client/tx.rs +++ b/apps/src/lib/client/tx.rs @@ -15,7 +15,8 @@ use namada::ledger::governance::storage as gov_storage; use namada::ledger::rpc::{TxBroadcastData, TxResponse}; use namada::ledger::signing::TxSigningKey; use namada::ledger::wallet::{Wallet, WalletUtils}; -use namada::ledger::{masp, tx}; +use namada::ledger::{masp, pos, tx}; +use namada::proof_of_stake::parameters::PosParams; use namada::proto::{Code, Data, Section, Tx}; use namada::types::address::Address; use namada::types::governance::{ @@ -39,6 +40,7 @@ use crate::cli::{args, safe_exit, Context}; use crate::client::rpc::query_wasm_code_hash; use crate::client::signing::find_keypair; use crate::client::tx::tx::ProcessTxResponse; +use crate::config::TendermintMode; use crate::facade::tendermint_rpc::endpoint::broadcast::tx_sync::Response; use crate::node::ledger::tendermint_node; use crate::wallet::{ @@ -294,6 +296,23 @@ pub async fn submit_init_validator< tendermint_node::write_validator_key(&tendermint_home, &consensus_key); tendermint_node::write_validator_state(tendermint_home); + // Write Namada config stuff or figure out how to do the above + // tendermint_node things two epochs in the future!!! + ctx.config.ledger.tendermint.tendermint_mode = + TendermintMode::Validator; + ctx.config + .write( + &ctx.config.ledger.shell.base_dir, + &ctx.config.ledger.chain_id, + true, + ) + .unwrap(); + + let key = pos::params_key(); + let pos_params = rpc::query_storage_value::(client, &key) + .await + .expect("Pos parameter should be defined."); + println!(); println!( "The validator's addresses and keys were stored in the wallet:" @@ -305,6 +324,11 @@ pub async fn submit_init_validator< "The ledger node has been setup to use this validator's address \ and consensus key." ); + println!( + "Your validator will be active in {} epochs. Be sure to restart \ + your node for the changes to take effect!", + pos_params.pipeline_len + ); } else { println!("Transaction dry run. No addresses have been saved.") } diff --git a/apps/src/lib/node/ledger/shell/prepare_proposal.rs b/apps/src/lib/node/ledger/shell/prepare_proposal.rs index 7d126a5218..9a9aa58491 100644 --- a/apps/src/lib/node/ledger/shell/prepare_proposal.rs +++ b/apps/src/lib/node/ledger/shell/prepare_proposal.rs @@ -25,7 +25,6 @@ use crate::facade::tendermint_proto::abci::RequestPrepareProposal; #[cfg(feature = "abcipp")] use crate::facade::tendermint_proto::abci::{tx_record::TxAction, TxRecord}; use crate::facade::tendermint_proto::google::protobuf::Timestamp; -use crate::node::ledger::shell::ShellMode; use crate::node::ledger::shims::abcipp_shim_types::shim::{response, TxBytes}; impl Shell @@ -45,36 +44,30 @@ where &self, req: RequestPrepareProposal, ) -> response::PrepareProposal { - let txs = if let ShellMode::Validator { .. } = self.mode { - // start counting allotted space for txs - let alloc = self.get_encrypted_txs_allocator(); - // add encrypted txs - let (encrypted_txs, alloc) = self.build_encrypted_txs( - alloc, - TempWlStorage::new(&self.wl_storage.storage), - &req.txs, - &req.time, - ); - let mut txs = encrypted_txs; - - // decrypt the wrapper txs included in the previous block - let (mut decrypted_txs, alloc) = self.build_decrypted_txs(alloc); - txs.append(&mut decrypted_txs); - - // add vote extension protocol txs - let mut protocol_txs = self.build_protocol_txs( - alloc, - #[cfg(feature = "abcipp")] - req.local_last_commit, - #[cfg(not(feature = "abcipp"))] - &req.txs, - ); - txs.append(&mut protocol_txs); - - txs - } else { - vec![] - }; + // start counting allotted space for txs + let alloc = self.get_encrypted_txs_allocator(); + // add encrypted txs + let (encrypted_txs, alloc) = self.build_encrypted_txs( + alloc, + TempWlStorage::new(&self.wl_storage.storage), + &req.txs, + &req.time, + ); + let mut txs = encrypted_txs; + + // decrypt the wrapper txs included in the previous block + let (mut decrypted_txs, alloc) = self.build_decrypted_txs(alloc); + txs.append(&mut decrypted_txs); + + // add vote extension protocol txs + let mut protocol_txs = self.build_protocol_txs( + alloc, + #[cfg(feature = "abcipp")] + req.local_last_commit, + #[cfg(not(feature = "abcipp"))] + &req.txs, + ); + txs.append(&mut protocol_txs); tracing::info!( height = req.height, diff --git a/tests/src/e2e/ledger_tests.rs b/tests/src/e2e/ledger_tests.rs index 22d837b1ad..5029bea080 100644 --- a/tests/src/e2e/ledger_tests.rs +++ b/tests/src/e2e/ledger_tests.rs @@ -2350,8 +2350,15 @@ All unbonds total withdrawable: 412\r", #[test] fn pos_init_validator() -> Result<()> { let pipeline_len = 1; + let validator_stake = 200000_u64; let test = setup::network( |genesis| { + assert_eq!( + genesis.validator.get("validator-0").unwrap().tokens, + Some(validator_stake), + "Assuming this stake, we give the same amount to the new \ + validator to have half of voting power", + ); let parameters = ParametersConfig { min_num_of_blocks: 4, epochs_per_year: 31_536_000, @@ -2372,16 +2379,28 @@ fn pos_init_validator() -> Result<()> { None, )?; - // 1. Run the ledger node - let mut ledger = - run_as!(test, Who::Validator(0), Bin::Node, &["ledger"], Some(40))?; + // 1. Run a validator and non-validator ledger node + let args = ["ledger"]; + let mut validator_0 = + run_as!(test, Who::Validator(0), Bin::Node, args, Some(60))?; + let mut non_validator = + run_as!(test, Who::NonValidator, Bin::Node, args, Some(60))?; - wait_for_wasm_pre_compile(&mut ledger)?; - let _bg_ledger = ledger.background(); + wait_for_wasm_pre_compile(&mut validator_0)?; + // let _bg_ledger = validator_0.background(); - let validator_one_rpc = get_actor_rpc(&test, &Who::Validator(0)); + wait_for_wasm_pre_compile(&mut non_validator)?; + // let _bg_ledger = non_validator.background(); + + // Wait for a first block + validator_0.exp_string("Committed block hash")?; + let _bg_validator_0 = validator_0.background(); + non_validator.exp_string("Committed block hash")?; + let bg_non_validator = non_validator.background(); + + let non_validator_rpc = get_actor_rpc(&test, &Who::NonValidator); - // 2. Initialize a new validator account + // 2. Initialize a new validator account with the non-validator node let new_validator = "new-validator"; let new_validator_key = format!("{}-key", new_validator); let tx_args = vec![ @@ -2402,7 +2421,7 @@ fn pos_init_validator() -> Result<()> { "--max-commission-rate-change", "0.01", "--node", - &validator_one_rpc, + &non_validator_rpc, ]; let mut client = run!(test, Bin::Client, tx_args, Some(40))?; client.exp_string("Transaction is valid.")?; @@ -2427,12 +2446,14 @@ fn pos_init_validator() -> Result<()> { "--gas-token", NAM, "--node", - &validator_one_rpc, + &non_validator_rpc, ]; let mut client = run!(test, Bin::Client, tx_args, Some(40))?; client.exp_string("Transaction is valid.")?; client.assert_success(); // Then self-bond the tokens: + let delegation = 5_u64; + let delegation_str = &delegation.to_string(); let tx_args = vec![ "bond", "--validator", @@ -2440,7 +2461,7 @@ fn pos_init_validator() -> Result<()> { "--source", BERTHA, "--amount", - "1000.5", + delegation_str, "--gas-amount", "0", "--gas-limit", @@ -2448,13 +2469,14 @@ fn pos_init_validator() -> Result<()> { "--gas-token", NAM, "--node", - &validator_one_rpc, + &non_validator_rpc, ]; let mut client = run!(test, Bin::Client, tx_args, Some(40))?; client.exp_string("Transaction is valid.")?; client.assert_success(); // 4. Transfer some NAM to the new validator + let validator_stake_str = &validator_stake.to_string(); let tx_args = vec![ "transfer", "--source", @@ -2464,7 +2486,7 @@ fn pos_init_validator() -> Result<()> { "--token", NAM, "--amount", - "10999.5", + validator_stake_str, "--gas-amount", "0", "--gas-limit", @@ -2472,7 +2494,7 @@ fn pos_init_validator() -> Result<()> { "--gas-token", NAM, "--node", - &validator_one_rpc, + &non_validator_rpc, ]; let mut client = run!(test, Bin::Client, tx_args, Some(40))?; client.exp_string("Transaction is valid.")?; @@ -2484,7 +2506,7 @@ fn pos_init_validator() -> Result<()> { "--validator", new_validator, "--amount", - "10000", + validator_stake_str, "--gas-amount", "0", "--gas-limit", @@ -2492,15 +2514,39 @@ fn pos_init_validator() -> Result<()> { "--gas-token", NAM, "--node", - &validator_one_rpc, + &non_validator_rpc, ]; let mut client = run!(test, Bin::Client, tx_args, Some(40))?; client.exp_string("Transaction is valid.")?; client.assert_success(); + // Stop the non-validator node and run it as the new validator + let mut non_validator = bg_non_validator.foreground(); + non_validator.interrupt()?; + + // it takes a bit before the node is shutdown. We dont want flasky test. + sleep(6); + + let loc = format!("{}:{}", std::file!(), std::line!()); + let validator_1_base_dir = test.get_base_dir(&Who::NonValidator); + let mut validator_1 = setup::run_cmd( + Bin::Node, + args, + Some(60), + &test.working_dir, + validator_1_base_dir, + None, + loc, + )?; + + validator_1.exp_string("Namada ledger node started")?; + validator_1.exp_string("This node is a validator")?; + validator_1.exp_string("Committed block hash")?; + let _bg_validator_1 = validator_1.background(); + // 6. Wait for the pipeline epoch when the validator's bonded stake should // be non-zero - let epoch = get_epoch(&test, &validator_one_rpc)?; + let epoch = get_epoch(&test, &non_validator_rpc)?; let earliest_update_epoch = epoch + pipeline_len; println!( "Current epoch: {}, earliest epoch with updated bonded stake: {}", @@ -2512,7 +2558,7 @@ fn pos_init_validator() -> Result<()> { if Instant::now().duration_since(start) > loop_timeout { panic!("Timed out waiting for epoch: {}", earliest_update_epoch); } - let epoch = get_epoch(&test, &validator_one_rpc)?; + let epoch = get_epoch(&test, &non_validator_rpc)?; if epoch >= earliest_update_epoch { break; } @@ -2520,8 +2566,11 @@ fn pos_init_validator() -> Result<()> { // 7. Check the new validator's bonded stake let bonded_stake = - find_bonded_stake(&test, new_validator, &validator_one_rpc)?; - assert_eq!(bonded_stake, token::Amount::from_str("11_000.5").unwrap()); + find_bonded_stake(&test, new_validator, &non_validator_rpc)?; + assert_eq!( + bonded_stake, + token::Amount::whole(validator_stake + delegation) + ); Ok(()) } @@ -3709,7 +3758,7 @@ fn test_genesis_validators() -> Result<()> { Some(5), &working_dir, &test_dir, - "validator", + None, format!("{}:{}", std::file!(), std::line!()), )?; init_genesis_validator_0.assert_success(); @@ -3751,7 +3800,7 @@ fn test_genesis_validators() -> Result<()> { Some(5), &working_dir, &test_dir, - "validator", + None, format!("{}:{}", std::file!(), std::line!()), )?; init_genesis_validator_1.assert_success(); @@ -3828,7 +3877,7 @@ fn test_genesis_validators() -> Result<()> { Some(5), &working_dir, &test_dir, - "validator", + None, format!("{}:{}", std::file!(), std::line!()), )?; @@ -4140,7 +4189,7 @@ fn double_signing_gets_slashed() -> Result<()> { Some(40), &test.working_dir, validator_0_base_dir_copy, - "validator", + None, loc, )?; validator_0_copy.exp_string("Namada ledger node started")?; diff --git a/tests/src/e2e/setup.rs b/tests/src/e2e/setup.rs index 114fed6cce..c6a8eb8959 100644 --- a/tests/src/e2e/setup.rs +++ b/tests/src/e2e/setup.rs @@ -167,7 +167,7 @@ pub fn network( Some(5), &working_dir, &test_dir, - "validator", + None, format!("{}:{}", std::file!(), std::line!()), )?; @@ -404,7 +404,7 @@ impl Test { timeout_sec, &self.working_dir, base_dir, - mode, + Some(mode), loc, ) } @@ -673,7 +673,7 @@ pub fn run_cmd( timeout_sec: Option, working_dir: impl AsRef, base_dir: impl AsRef, - mode: &str, + mode: Option<&str>, loc: String, ) -> Result where @@ -697,13 +697,13 @@ where .env("TM_LOG_LEVEL", "info") .env("NAMADA_LOG_COLOR", "false") .current_dir(working_dir) - .args([ - "--base-dir", - &base_dir.as_ref().to_string_lossy(), - "--mode", - mode, - ]) - .args(args); + .args(["--base-dir", &base_dir.as_ref().to_string_lossy()]); + + if let Some(mode) = mode { + run_cmd.args(["--mode", mode]); + } + + run_cmd.args(args); let args: String = run_cmd.get_args().map(|s| s.to_string_lossy()).join(" ");