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/.changelog/unreleased/bug-fixes/1553-fix-is-validator-fn.md b/.changelog/unreleased/bug-fixes/1553-fix-is-validator-fn.md new file mode 100644 index 0000000000..c66e587913 --- /dev/null +++ b/.changelog/unreleased/bug-fixes/1553-fix-is-validator-fn.md @@ -0,0 +1,3 @@ +- PoS: fixed a check for whether a given address belongs to a + validator account to work properly with newly created accounts. + ([\#1553](https://github.com/anoma/namada/pull/1553)) \ No newline at end of file diff --git a/apps/src/lib/client/tx.rs b/apps/src/lib/client/tx.rs index 20bcf7f83b..05f2897060 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::{ @@ -292,6 +294,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:" @@ -303,6 +322,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/proof_of_stake/src/lib.rs b/proof_of_stake/src/lib.rs index b1fdb82bc0..1c9e475ff9 100644 --- a/proof_of_stake/src/lib.rs +++ b/proof_of_stake/src/lib.rs @@ -808,14 +808,12 @@ where pub fn is_validator( storage: &S, address: &Address, - params: &PosParams, - epoch: namada_core::types::storage::Epoch, ) -> storage_api::Result where S: StorageRead + StorageWrite, { - let state = validator_state_handle(address).get(storage, epoch, params)?; - Ok(state.is_some()) + let rate = read_validator_max_commission_rate_change(storage, address)?; + Ok(rate.is_some()) } /// Check if the provided address is a delegator address, optionally at a @@ -868,9 +866,7 @@ where let params = read_pos_params(storage)?; let pipeline_epoch = current_epoch + params.pipeline_len; if let Some(source) = source { - if source != validator - && is_validator(storage, source, ¶ms, pipeline_epoch)? - { + if source != validator && is_validator(storage, source)? { return Err( BondError::SourceMustNotBeAValidator(source.clone()).into() ); @@ -1534,16 +1530,14 @@ where // Make sure source is not some other validator if let Some(source) = source { - if source != validator - && is_validator(storage, source, ¶ms, pipeline_epoch)? - { + if source != validator && is_validator(storage, source)? { return Err( BondError::SourceMustNotBeAValidator(source.clone()).into() ); } } // Make sure the target is actually a validator - if !is_validator(storage, validator, ¶ms, pipeline_epoch)? { + if !is_validator(storage, validator)? { return Err(BondError::NotAValidator(validator.clone()).into()); } // Make sure the validator is not currently frozen diff --git a/proof_of_stake/src/tests.rs b/proof_of_stake/src/tests.rs index edc01d3c35..08dcde453f 100644 --- a/proof_of_stake/src/tests.rs +++ b/proof_of_stake/src/tests.rs @@ -40,7 +40,7 @@ use crate::{ bond_tokens, bonds_and_unbonds, consensus_validator_set_handle, copy_validator_sets_and_positions, find_validator_by_raw_hash, get_num_consensus_validators, init_genesis, - insert_validator_into_validator_set, process_slashes, + insert_validator_into_validator_set, is_validator, process_slashes, read_below_capacity_validator_set_addresses_with_stake, read_consensus_validator_set_addresses_with_stake, read_total_stake, read_validator_delta_value, read_validator_stake, slash, @@ -789,6 +789,7 @@ fn test_become_validator_aux( min(validators.len() as u64, params.max_validator_slots), num_consensus_before ); + assert!(!is_validator(&s, &new_validator).unwrap()); // Initialize the validator account let consensus_key = new_validator_consensus_key.to_public(); @@ -802,6 +803,7 @@ fn test_become_validator_aux( Decimal::new(5, 2), ) .unwrap(); + assert!(is_validator(&s, &new_validator).unwrap()); let num_consensus_after = get_num_consensus_validators(&s, current_epoch + params.pipeline_len) diff --git a/proof_of_stake/src/tests/state_machine.rs b/proof_of_stake/src/tests/state_machine.rs index 85d1758e26..2e8b0c4d25 100644 --- a/proof_of_stake/src/tests/state_machine.rs +++ b/proof_of_stake/src/tests/state_machine.rs @@ -249,13 +249,7 @@ impl StateMachineTest for ConcretePosState { // This must be ensured by both transitions generator and // pre-conditions! assert!( - crate::is_validator( - &state.s, - &id.validator, - ¶ms, - pipeline, - ) - .unwrap(), + crate::is_validator(&state.s, &id.validator).unwrap(), "{} is not a validator", id.validator ); diff --git a/shared/src/ledger/queries/vp/pos.rs b/shared/src/ledger/queries/vp/pos.rs index 81fc3f681b..dd0e561514 100644 --- a/shared/src/ledger/queries/vp/pos.rs +++ b/shared/src/ledger/queries/vp/pos.rs @@ -98,13 +98,7 @@ where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, { - let params = namada_proof_of_stake::read_pos_params(ctx.wl_storage)?; - namada_proof_of_stake::is_validator( - ctx.wl_storage, - &addr, - ¶ms, - ctx.wl_storage.storage.block.epoch, - ) + namada_proof_of_stake::is_validator(ctx.wl_storage, &addr) } /// Find if the given address is a delegator diff --git a/tests/src/e2e/ledger_tests.rs b/tests/src/e2e/ledger_tests.rs index d4c910807c..8328abd34d 100644 --- a/tests/src/e2e/ledger_tests.rs +++ b/tests/src/e2e/ledger_tests.rs @@ -2352,8 +2352,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, @@ -2374,17 +2381,22 @@ 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(40))?; + let mut non_validator = + run_as!(test, Who::NonValidator, Bin::Node, args, Some(40))?; // Wait for a first block - ledger.exp_string("Committed block hash")?; - let _bg_ledger = ledger.background(); + 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 validator_one_rpc = get_actor_rpc(&test, &Who::Validator(0)); + 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![ @@ -2405,7 +2417,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.")?; @@ -2430,12 +2442,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", @@ -2443,7 +2457,7 @@ fn pos_init_validator() -> Result<()> { "--source", BERTHA, "--amount", - "1000.5", + delegation_str, "--gas-amount", "0", "--gas-limit", @@ -2451,13 +2465,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", @@ -2467,7 +2482,7 @@ fn pos_init_validator() -> Result<()> { "--token", NAM, "--amount", - "10999.5", + validator_stake_str, "--gas-amount", "0", "--gas-limit", @@ -2475,7 +2490,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.")?; @@ -2487,7 +2502,7 @@ fn pos_init_validator() -> Result<()> { "--validator", new_validator, "--amount", - "10000", + validator_stake_str, "--gas-amount", "0", "--gas-limit", @@ -2495,15 +2510,34 @@ 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()?; + 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(40), + &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_non_validator = non_validator.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: {}", @@ -2515,7 +2549,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; } @@ -2523,8 +2557,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(()) } @@ -3713,7 +3750,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(); @@ -3755,7 +3792,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(); @@ -3832,7 +3869,7 @@ fn test_genesis_validators() -> Result<()> { Some(5), &working_dir, &test_dir, - "validator", + None, format!("{}:{}", std::file!(), std::line!()), )?; @@ -4145,7 +4182,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(" "); diff --git a/wasm/checksums.json b/wasm/checksums.json index 718af73cca..8e2e714b1b 100644 --- a/wasm/checksums.json +++ b/wasm/checksums.json @@ -1,17 +1,17 @@ { - "tx_bond.wasm": "tx_bond.9d034041d7085d261e2d75e548b74e0635b7c87f14173aecddbd64d8a8646d58.wasm", - "tx_change_validator_commission.wasm": "tx_change_validator_commission.5d172f38a22a045902e83d10ebdcaef88f75a0511dc5c3e224ef89d7fc594b78.wasm", + "tx_bond.wasm": "tx_bond.4f5c6ca2ac0e933ab9d7370743de4950f95f5ad3ccb3d3a45ab42daa1e69506f.wasm", + "tx_change_validator_commission.wasm": "tx_change_validator_commission.9c8d8fe732a794bc00fe9247d5e28a6b4df6959018140a05161c27ac68aab853.wasm", "tx_ibc.wasm": "tx_ibc.462075ed66348d74f60a7af04d5200acff673ddb1a1d16497fbc97ee846e1851.wasm", "tx_init_account.wasm": "tx_init_account.7e827fb86331b0b62eb1162f917e522f6f426df9608d67c13caed089d63cd25f.wasm", "tx_init_proposal.wasm": "tx_init_proposal.4fe5500d95d040ca3f2e51446bfb96cfc99596302e4e2368ee599f1a610f5968.wasm", "tx_init_validator.wasm": "tx_init_validator.a6db44f07090f6c19dea71f1865f6acba1a4a946c29057231312188dfbfd1c9e.wasm", "tx_reveal_pk.wasm": "tx_reveal_pk.3bb71bb884737ab184b4f543b503e512431d0e8cad24d202981c06063a11614c.wasm", "tx_transfer.wasm": "tx_transfer.8c24cc4bb4e947a7fab4708039300cfa36b0513db55e6ca45b1d7276db1eb02c.wasm", - "tx_unbond.wasm": "tx_unbond.99aacaa049edea0704a147d2feb79702fbae8a014092f41b8483daeff5eee181.wasm", - "tx_unjail_validator.wasm": "tx_unjail_validator.d9fe28aadc5d21d9d0c8e89365e5e8e68420c8f5c15c5c12c8587120822b9ceb.wasm", + "tx_unbond.wasm": "tx_unbond.88b522ab08abe228d6deb2716060cfc1db9ebff016c3d97a8b94d80126b96aab.wasm", + "tx_unjail_validator.wasm": "tx_unjail_validator.4cad94633f701614c891c74a7d829dd44cd39ee0aebf6a6921ccea1bb9333214.wasm", "tx_update_vp.wasm": "tx_update_vp.c5706b7f5223deb15f2fae1646ee487948dd0ac25450ca460d9dfa55f29ab2c5.wasm", "tx_vote_proposal.wasm": "tx_vote_proposal.df21ee966e13f9c5731deea7c8a2ed62612d4706691b35564b058ed175b476ef.wasm", - "tx_withdraw.wasm": "tx_withdraw.cbb043216f2fc75b88a32bd3fbad8a05b48df4c3d6bdbc8284606a71b9be9d38.wasm", + "tx_withdraw.wasm": "tx_withdraw.0f4a54d0158937f50df7077baf78766bb2549361015f27d911810aea4228358a.wasm", "vp_implicit.wasm": "vp_implicit.c3b78b8b0bb9072a9a4c9e2aa1e89e04db9fdc41eecd53850698bfea89631103.wasm", "vp_masp.wasm": "vp_masp.8c4ea33db73f13ad9c6efd1634780fd872e7acadb5a615e96f4b2cbbf8626463.wasm", "vp_testnet_faucet.wasm": "vp_testnet_faucet.403d3d09e582968305223e66a0c35c7b91fd62ac9bc07bab32250bc9120d2114.wasm",