diff --git a/.changelog/unreleased/improvements/3497-di-pos.md b/.changelog/unreleased/improvements/3497-di-pos.md new file mode 100644 index 00000000000..5bb3b1551cb --- /dev/null +++ b/.changelog/unreleased/improvements/3497-di-pos.md @@ -0,0 +1,2 @@ +- Replaced cross-system dependencies in namada_proof_of_stake crate with + dependency-injection. ([\#3497](https://github.com/anoma/namada/pull/3497)) \ No newline at end of file diff --git a/.changelog/unreleased/improvements/3509-di-ibc.md b/.changelog/unreleased/improvements/3509-di-ibc.md new file mode 100644 index 00000000000..db62d759328 --- /dev/null +++ b/.changelog/unreleased/improvements/3509-di-ibc.md @@ -0,0 +1,2 @@ +- Replaced cross-system dependencies in namada_ibc crate with dependency- + injection. ([\#3509](https://github.com/anoma/namada/pull/3509)) \ No newline at end of file diff --git a/.changelog/unreleased/improvements/3577-relax-bounds.md b/.changelog/unreleased/improvements/3577-relax-bounds.md new file mode 100644 index 00000000000..ad8b64ede28 --- /dev/null +++ b/.changelog/unreleased/improvements/3577-relax-bounds.md @@ -0,0 +1,2 @@ +- Removed unnecessary trait bound from declarations. + ([\#3577](https://github.com/anoma/namada/pull/3577)) \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index e0e75606fa7..c2548b03da8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4674,6 +4674,7 @@ dependencies = [ "namada_core", "namada_events", "namada_gas", + "namada_governance", "namada_macros", "namada_migrations", "namada_parameters", @@ -4762,6 +4763,7 @@ dependencies = [ "namada_gas", "namada_macros", "namada_migrations", + "namada_parameters", "namada_proof_of_stake", "namada_state", "namada_systems", diff --git a/crates/benches/native_vps.rs b/crates/benches/native_vps.rs index 36e561c865b..c5111a618ca 100644 --- a/crates/benches/native_vps.rs +++ b/crates/benches/native_vps.rs @@ -51,7 +51,7 @@ use namada_apps_lib::validation::{ IbcVpContext, MaspVp, MultitokenVp, ParametersVp, PgfVp, PosVp, }; use namada_apps_lib::wallet::defaults; -use namada_apps_lib::{governance, proof_of_stake, storage, token}; +use namada_apps_lib::{governance, parameters, proof_of_stake, storage, token}; use namada_node::bench_utils::{ generate_foreign_key_tx, BenchShell, BenchShieldedCtx, ALBERT_PAYMENT_ADDRESS, ALBERT_SPENDING_KEY, BERTHA_PAYMENT_ADDRESS, @@ -110,9 +110,11 @@ fn governance(c: &mut Criterion) { "minimal_proposal" => { let content_section = Section::ExtraData(Code::new(vec![], None)); - let params = - proof_of_stake::storage::read_pos_params(&shell.state) - .unwrap(); + let params = proof_of_stake::storage::read_pos_params::< + _, + governance::Store<_>, + >(&shell.state) + .unwrap(); let voting_start_epoch = Epoch(2 + params.pipeline_len + params.unbonding_len); // Must start after current epoch @@ -163,9 +165,11 @@ fn governance(c: &mut Criterion) { None, )); - let params = - proof_of_stake::storage::read_pos_params(&shell.state) - .unwrap(); + let params = proof_of_stake::storage::read_pos_params::< + _, + governance::Store<_>, + >(&shell.state) + .unwrap(); let voting_start_epoch = Epoch(2 + params.pipeline_len + params.unbonding_len); // Must start after current epoch @@ -1670,16 +1674,20 @@ fn ibc_vp_validate_action(c: &mut Criterion) { let exec_ctx = IbcVpContext::new(ibc.ctx.pre()); let ctx = Rc::new(RefCell::new(exec_ctx)); - let mut actions = IbcActions::new(ctx.clone(), verifiers.clone()); + let mut actions = + IbcActions::<_, parameters::Store<_>, token::Store<()>>::new( + ctx.clone(), + verifiers.clone(), + ); actions.set_validation_params(ibc.validation_params().unwrap()); let module = TransferModule::new(ctx.clone(), verifiers); actions.add_transfer_module(module); - let module = NftTransferModule::new(ctx); + let module = NftTransferModule::<_, token::Store<()>>::new(ctx); actions.add_transfer_module(module); group.bench_function(bench_name, |b| { - b.iter(|| actions.validate(&tx_data).unwrap()) + b.iter(|| actions.validate::(&tx_data).unwrap()) }); } @@ -1727,16 +1735,20 @@ fn ibc_vp_execute_action(c: &mut Criterion) { let exec_ctx = IbcVpContext::new(ibc.ctx.pre()); let ctx = Rc::new(RefCell::new(exec_ctx)); - let mut actions = IbcActions::new(ctx.clone(), verifiers.clone()); + let mut actions = + IbcActions::<_, parameters::Store<_>, token::Store<()>>::new( + ctx.clone(), + verifiers.clone(), + ); actions.set_validation_params(ibc.validation_params().unwrap()); let module = TransferModule::new(ctx.clone(), verifiers); actions.add_transfer_module(module); - let module = NftTransferModule::new(ctx); + let module = NftTransferModule::<_, token::Store<()>>::new(ctx); actions.add_transfer_module(module); group.bench_function(bench_name, |b| { - b.iter(|| actions.execute(&tx_data).unwrap()) + b.iter(|| actions.execute::(&tx_data).unwrap()) }); } diff --git a/crates/core/src/ibc.rs b/crates/core/src/ibc.rs index 4f0f62ecaaf..39a4b505d88 100644 --- a/crates/core/src/ibc.rs +++ b/crates/core/src/ibc.rs @@ -1,10 +1,12 @@ //! IBC-related data types +use std::collections::BTreeMap; use std::fmt::Display; use std::str::FromStr; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use data_encoding::{DecodePartial, HEXLOWER, HEXLOWER_PERMISSIVE}; +use ibc::core::host::types::identifiers::{ChannelId, PortId}; pub use ibc::*; use namada_macros::BorshDeserializer; #[cfg(feature = "migrations")] @@ -13,6 +15,7 @@ use serde::{Deserialize, Serialize}; use super::address::HASH_LEN; use crate::hash::Hash; +use crate::token; /// IBC token hash derived from a denomination. #[derive( @@ -70,3 +73,92 @@ impl FromStr for IbcTxDataRefs { serde_json::from_str(s) } } + +/// The target of a PGF payment +#[derive( + Debug, + Clone, + PartialEq, + Serialize, + Deserialize, + Ord, + Eq, + PartialOrd, + BorshDeserializer, + Hash, +)] +pub struct PGFIbcTarget { + /// The target address on the target chain + pub target: String, + /// The amount of token to fund the target address + pub amount: token::Amount, + /// Port ID to fund + pub port_id: PortId, + /// Channel ID to fund + pub channel_id: ChannelId, +} + +impl BorshSerialize for PGFIbcTarget { + fn serialize( + &self, + writer: &mut W, + ) -> std::io::Result<()> { + BorshSerialize::serialize(&self.target, writer)?; + BorshSerialize::serialize(&self.amount, writer)?; + BorshSerialize::serialize(&self.port_id.to_string(), writer)?; + BorshSerialize::serialize(&self.channel_id.to_string(), writer) + } +} + +impl borsh::BorshDeserialize for PGFIbcTarget { + fn deserialize_reader( + reader: &mut R, + ) -> std::io::Result { + use std::io::{Error, ErrorKind}; + let target: String = BorshDeserialize::deserialize_reader(reader)?; + let amount: token::Amount = + BorshDeserialize::deserialize_reader(reader)?; + let port_id: String = BorshDeserialize::deserialize_reader(reader)?; + let port_id: PortId = port_id.parse().map_err(|err| { + Error::new( + ErrorKind::InvalidData, + format!("Error decoding port ID: {}", err), + ) + })?; + let channel_id: String = BorshDeserialize::deserialize_reader(reader)?; + let channel_id: ChannelId = channel_id.parse().map_err(|err| { + Error::new( + ErrorKind::InvalidData, + format!("Error decoding channel ID: {}", err), + ) + })?; + Ok(Self { + target, + amount, + port_id, + channel_id, + }) + } +} + +impl borsh::BorshSchema for PGFIbcTarget { + fn add_definitions_recursively( + definitions: &mut BTreeMap< + borsh::schema::Declaration, + borsh::schema::Definition, + >, + ) { + let fields = borsh::schema::Fields::NamedFields(vec![ + ("target".into(), String::declaration()), + ("amount".into(), token::Amount::declaration()), + ("port_id".into(), String::declaration()), + ("channel_id".into(), String::declaration()), + ]); + let definition = borsh::schema::Definition::Struct { fields }; + definitions.insert(Self::declaration(), definition); + } + + fn declaration() -> borsh::schema::Declaration { + std::any::type_name::().into() + } +} diff --git a/crates/ethereum_bridge/Cargo.toml b/crates/ethereum_bridge/Cargo.toml index 49cc6e9c4f5..9cf79413b04 100644 --- a/crates/ethereum_bridge/Cargo.toml +++ b/crates/ethereum_bridge/Cargo.toml @@ -19,6 +19,7 @@ testing = [ "namada_account", "namada_core/testing", "namada_state/testing", + "namada_governance", ] migrations = [ "namada_migrations", @@ -29,6 +30,7 @@ migrations = [ namada_account = {path = "../account", optional = true} namada_core = {path = "../core", default-features = false, features = ["ethers-derive"]} namada_events = { path = "../events", default-features = false } +namada_governance = {path = "../governance", optional = true} namada_macros = {path = "../macros"} namada_migrations = {path = "../migrations", optional = true} namada_parameters = {path = "../parameters"} @@ -53,10 +55,10 @@ thiserror.workspace = true tracing = "0.1.30" [dev-dependencies] -# Added "testing" feature. namada_account = {path = "../account"} namada_core = {path = "../core", default-features = false, features = ["ethers-derive", "testing"]} namada_gas = {path = "../gas"} +namada_governance = {path = "../governance"} namada_proof_of_stake = {path = "../proof_of_stake", default-features = false, features = ["testing"]} namada_state = { path = "../state", features = ["testing"] } namada_token = {path = "../token", features = ["testing"]} diff --git a/crates/ethereum_bridge/src/protocol/transactions/bridge_pool_roots.rs b/crates/ethereum_bridge/src/protocol/transactions/bridge_pool_roots.rs index ce2dfef8d6b..b71b5cd104a 100644 --- a/crates/ethereum_bridge/src/protocol/transactions/bridge_pool_roots.rs +++ b/crates/ethereum_bridge/src/protocol/transactions/bridge_pool_roots.rs @@ -7,9 +7,9 @@ use namada_core::keccak::keccak_hash; use namada_core::key::{common, SignableEthMessage}; use namada_core::storage::BlockHeight; use namada_core::token::Amount; -use namada_proof_of_stake::pos_queries::PosQueries; use namada_state::{DBIter, StorageHasher, WlState, DB}; use namada_storage::{StorageRead, StorageWrite}; +use namada_systems::governance; use namada_tx::data::BatchedTxResult; use namada_tx::Signed; use namada_vote_ext::bridge_pool_roots::{self, MultiSignedVext, SignedVext}; @@ -58,13 +58,14 @@ where /// For roots + nonces which have been seen by a quorum of /// validators, the signature is made available for bridge /// pool proofs. -pub fn apply_derived_tx( +pub fn apply_derived_tx( state: &mut WlState, vext: MultiSignedVext, ) -> Result where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, + Gov: governance::Read>, { if vext.is_empty() { return Ok(BatchedTxResult::default()); @@ -76,7 +77,7 @@ where ); let voting_powers = utils::get_voting_powers(state, &vext)?; let root_height = vext.iter().next().unwrap().data.block_height; - let (partial_proof, seen_by) = parse_vexts(state, vext); + let (partial_proof, seen_by) = parse_vexts::(state, vext); // return immediately if a complete proof has already been acquired let bp_key = vote_tallies::Keys::from((&partial_proof, root_height)); @@ -92,8 +93,13 @@ where } // apply updates to the bridge pool root. - let (mut changed, confirmed_update) = - apply_update(state, bp_key, partial_proof, seen_by, &voting_powers)?; + let (mut changed, confirmed_update) = apply_update::( + state, + bp_key, + partial_proof, + seen_by, + &voting_powers, + )?; // if the root is confirmed, update storage and add // relevant key to changed. @@ -150,16 +156,17 @@ impl GetVoters for &MultiSignedVext { /// Convert a set of signatures over bridge pool roots and nonces (at a certain /// height) into a partial proof and a new set of votes. -fn parse_vexts( +fn parse_vexts( state: &WlState, multisigned: MultiSignedVext, ) -> (BridgePoolRoot, Votes) where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, + Gov: governance::Read>, { let height = multisigned.iter().next().unwrap().data.block_height; - let epoch = state.pos_queries().get_epoch(height); + let epoch = state.get_epoch_at_height(height).unwrap(); let root = state .ethbridge_queries() .get_bridge_pool_root_at_height(height) @@ -173,7 +180,10 @@ where ( state .ethbridge_queries() - .get_eth_addr_book(&signed.data.validator_addr, epoch) + .get_eth_addr_book::( + &signed.data.validator_addr, + epoch, + ) .unwrap(), signed.data.sig, ) @@ -195,7 +205,7 @@ where /// indicating that it has been confirmed. /// /// In all instances, the changed storage keys are returned. -fn apply_update( +fn apply_update( state: &mut WlState, bp_key: vote_tallies::Keys, mut update: BridgePoolRoot, @@ -205,6 +215,7 @@ fn apply_update( where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, + Gov: governance::Read>, { let partial_proof = votes::storage::read_body(state, &bp_key); let (vote_tracking, changed, confirmed, already_present) = if let Ok( @@ -218,8 +229,9 @@ where ); update.0.attach_signature_batch(partial.0.signatures); let new_votes = NewVotes::new(seen_by, voting_powers)?; - let (vote_tracking, changed) = - votes::update::calculate(state, &bp_key, new_votes)?; + let (vote_tracking, changed) = votes::update::calculate::( + state, &bp_key, new_votes, + )?; if changed.is_empty() { return Ok((changed, None)); } @@ -227,7 +239,8 @@ where (vote_tracking, changed, confirmed, true) } else { tracing::debug!(%bp_key.prefix, "No validator has signed this bridge pool update before."); - let vote_tracking = calculate_new(state, seen_by, voting_powers)?; + let vote_tracking = + calculate_new::(state, seen_by, voting_powers)?; let changed = bp_key.into_iter().collect(); let confirmed = vote_tracking.seen; (vote_tracking, changed, confirmed, false) @@ -245,6 +258,7 @@ where #[cfg(test)] mod test_apply_bp_roots_to_storage { + use std::collections::BTreeSet; use assert_matches::assert_matches; @@ -254,7 +268,10 @@ mod test_apply_bp_roots_to_storage { use namada_core::storage::Key; use namada_core::voting_power::FractionalVotingPower; use namada_proof_of_stake::parameters::OwnedPosParams; - use namada_proof_of_stake::storage::write_pos_params; + use namada_proof_of_stake::queries::get_total_voting_power; + use namada_proof_of_stake::storage::{ + read_consensus_validator_set_addresses_with_stake, write_pos_params, + }; use namada_state::testing::TestState; use super::*; @@ -263,7 +280,7 @@ mod test_apply_bp_roots_to_storage { }; use crate::storage::bridge_pool::{get_key_from_hash, get_nonce_key}; use crate::storage::vp; - use crate::test_utils; + use crate::test_utils::{self, GovStore}; /// The data needed to run a test. struct TestPackage { @@ -344,7 +361,8 @@ mod test_apply_bp_roots_to_storage { } .sign(&keys[&validators[0]].protocol); let BatchedTxResult { changed_keys, .. } = - apply_derived_tx(&mut state, vext.into()).expect("Test failed"); + apply_derived_tx::<_, _, GovStore<_>>(&mut state, vext.into()) + .expect("Test failed"); let bp_root_key = vote_tallies::Keys::from(( &BridgePoolRoot(BridgePoolRootProof::new((root, nonce))), 100.into(), @@ -361,7 +379,8 @@ mod test_apply_bp_roots_to_storage { .sign(&keys[&validators[2]].protocol); let BatchedTxResult { changed_keys, .. } = - apply_derived_tx(&mut state, vext.into()).expect("Test failed"); + apply_derived_tx::<_, _, GovStore<_>>(&mut state, vext.into()) + .expect("Test failed"); let expected: BTreeSet = [bp_root_key.seen_by(), bp_root_key.voting_power()] @@ -401,7 +420,8 @@ mod test_apply_bp_roots_to_storage { .sign(&keys[&validators[1]].protocol); vexts.insert(vext); let BatchedTxResult { changed_keys, .. } = - apply_derived_tx(&mut state, vexts).expect("Test failed"); + apply_derived_tx::<_, _, GovStore<_>>(&mut state, vexts) + .expect("Test failed"); let bp_root_key = vote_tallies::Keys::from(( &BridgePoolRoot(BridgePoolRootProof::new((root, nonce))), 100.into(), @@ -433,7 +453,8 @@ mod test_apply_bp_roots_to_storage { .sig, } .sign(&keys[&validators[0]].protocol); - _ = apply_derived_tx(&mut state, vext.into()).expect("Test failed"); + _ = apply_derived_tx::<_, _, GovStore<_>>(&mut state, vext.into()) + .expect("Test failed"); let hot_key = &keys[&validators[1]].eth_bridge; let vext = bridge_pool_roots::Vext { @@ -443,7 +464,8 @@ mod test_apply_bp_roots_to_storage { } .sign(&keys[&validators[1]].protocol); let BatchedTxResult { changed_keys, .. } = - apply_derived_tx(&mut state, vext.into()).expect("Test failed"); + apply_derived_tx::<_, _, GovStore<_>>(&mut state, vext.into()) + .expect("Test failed"); let bp_root_key = vote_tallies::Keys::from(( &BridgePoolRoot(BridgePoolRootProof::new((root, nonce))), 100.into(), @@ -483,12 +505,13 @@ mod test_apply_bp_roots_to_storage { .sig, } .sign(&keys[&validators[0]].protocol); - _ = apply_derived_tx(&mut state, vext.into()).expect("Test failed"); + _ = apply_derived_tx::<_, _, GovStore<_>>(&mut state, vext.into()) + .expect("Test failed"); let voting_power = state .read::(&bp_root_key.voting_power()) .expect("Test failed") .expect("Test failed") - .fractional_stake(&state); + .fractional_stake::<_, _, GovStore<_>>(&state); assert_eq!( voting_power, FractionalVotingPower::new_u64(5, 12).unwrap() @@ -501,12 +524,13 @@ mod test_apply_bp_roots_to_storage { sig: Signed::<_, SignableEthMessage>::new(hot_key, to_sign).sig, } .sign(&keys[&validators[1]].protocol); - _ = apply_derived_tx(&mut state, vext.into()).expect("Test failed"); + _ = apply_derived_tx::<_, _, GovStore<_>>(&mut state, vext.into()) + .expect("Test failed"); let voting_power = state .read::(&bp_root_key.voting_power()) .expect("Test failed") .expect("Test failed") - .fractional_stake(&state); + .fractional_stake::<_, _, GovStore<_>>(&state); assert_eq!(voting_power, FractionalVotingPower::new_u64(5, 6).unwrap()); } @@ -535,7 +559,8 @@ mod test_apply_bp_roots_to_storage { .sig, } .sign(&keys[&validators[0]].protocol); - _ = apply_derived_tx(&mut state, vext.into()).expect("Test failed"); + _ = apply_derived_tx::<_, _, GovStore<_>>(&mut state, vext.into()) + .expect("Test failed"); let seen: bool = state .read(&bp_root_key.seen()) @@ -550,7 +575,8 @@ mod test_apply_bp_roots_to_storage { sig: Signed::<_, SignableEthMessage>::new(hot_key, to_sign).sig, } .sign(&keys[&validators[1]].protocol); - _ = apply_derived_tx(&mut state, vext.into()).expect("Test failed"); + _ = apply_derived_tx::<_, _, GovStore<_>>(&mut state, vext.into()) + .expect("Test failed"); let seen: bool = state .read(&bp_root_key.seen()) @@ -584,7 +610,8 @@ mod test_apply_bp_roots_to_storage { .sig, } .sign(&keys[&validators[0]].protocol); - _ = apply_derived_tx(&mut state, vext.into()).expect("Test failed"); + _ = apply_derived_tx::<_, _, GovStore<_>>(&mut state, vext.into()) + .expect("Test failed"); let expected = Votes::from([(validators[0].clone(), 100.into())]); let seen_by: Votes = state @@ -600,7 +627,8 @@ mod test_apply_bp_roots_to_storage { sig: Signed::<_, SignableEthMessage>::new(hot_key, to_sign).sig, } .sign(&keys[&validators[1]].protocol); - _ = apply_derived_tx(&mut state, vext.into()).expect("Test failed"); + _ = apply_derived_tx::<_, _, GovStore<_>>(&mut state, vext.into()) + .expect("Test failed"); let expected = Votes::from([ (validators[0].clone(), 100.into()), @@ -637,15 +665,16 @@ mod test_apply_bp_roots_to_storage { expected.0.attach_signature( state .ethbridge_queries() - .get_eth_addr_book( + .get_eth_addr_book::>( &validators[0], - state.pos_queries().get_epoch(100.into()), + state.get_epoch_at_height(100.into()).unwrap(), ) .expect("Test failed"), vext.sig.clone(), ); let vext = vext.sign(&keys[&validators[0]].protocol); - _ = apply_derived_tx(&mut state, vext.into()).expect("Test failed"); + _ = apply_derived_tx::<_, _, GovStore<_>>(&mut state, vext.into()) + .expect("Test failed"); let proof: BridgePoolRootProof = state .read(&bp_root_key.body()) @@ -694,21 +723,25 @@ mod test_apply_bp_roots_to_storage { .sign(&keys[&validators[1]].protocol); vexts.insert(vext); - let epoch = state.pos_queries().get_epoch(100.into()); + let epoch = state.get_epoch_at_height(100.into()).unwrap(); let sigs: Vec<_> = vexts .iter() .map(|s| { ( state .ethbridge_queries() - .get_eth_addr_book(&s.data.validator_addr, epoch) + .get_eth_addr_book::>( + &s.data.validator_addr, + epoch, + ) .expect("Test failed"), s.data.sig.clone(), ) }) .collect(); - _ = apply_derived_tx(&mut state, vexts).expect("Test failed"); + _ = apply_derived_tx::<_, _, GovStore<_>>(&mut state, vexts) + .expect("Test failed"); let (proof, _): (BridgePoolRootProof, BlockHeight) = state .read(&get_signed_root_key()) .expect("Test failed") @@ -759,14 +792,16 @@ mod test_apply_bp_roots_to_storage { macro_rules! query_validators { () => { |epoch: u64| { - state - .pos_queries() - .get_consensus_validators(Some(epoch.into())) - .iter() - .map(|validator| { - (validator.address, validator.bonded_stake) - }) - .collect::>() + read_consensus_validator_set_addresses_with_stake( + &state, + epoch.into(), + ) + .unwrap() + .into_iter() + .map(|validator| { + (validator.address, validator.bonded_stake) + }) + .collect::>() } }; } @@ -779,7 +814,7 @@ mod test_apply_bp_roots_to_storage { HashMap::from([(validator_1.clone(), validator_1_stake)]) ); assert_eq!( - state.pos_queries().get_total_voting_power(Some(0.into())), + get_total_voting_power::<_, GovStore<_>>(&state, 0.into()), validator_1_stake, ); assert_eq!( @@ -791,7 +826,7 @@ mod test_apply_bp_roots_to_storage { ]) ); assert_eq!( - state.pos_queries().get_total_voting_power(Some(1.into())), + get_total_voting_power::<_, GovStore<_>>(&state, 1.into()), validator_1_stake + validator_2_stake + validator_3_stake, ); @@ -815,7 +850,8 @@ mod test_apply_bp_roots_to_storage { } .sign(&keys[&validator_1].protocol); - _ = apply_derived_tx(&mut state, vext.into()).expect("Test failed"); + _ = apply_derived_tx::<_, _, GovStore<_>>(&mut state, vext.into()) + .expect("Test failed"); // query validator set of the proof // (should be the one from epoch 0) @@ -824,8 +860,8 @@ mod test_apply_bp_roots_to_storage { .get_signed_bridge_pool_root() .expect("Test failed"); let root_epoch = state - .pos_queries() - .get_epoch(root_height) + .get_epoch_at_height(root_height) + .unwrap() .expect("Test failed"); let query_validators = query_validators!(); @@ -861,8 +897,11 @@ mod test_apply_bp_roots_to_storage { .sig, } .sign(&keys[&validators[0]].protocol); - _ = apply_derived_tx(&mut state, vext.into()) - .expect("Test failed"); + _ = apply_derived_tx::<_, _, GovStore<_>>( + &mut state, + vext.into(), + ) + .expect("Test failed"); let hot_key = &keys[&validators[1]].eth_bridge; let vext = bridge_pool_roots::Vext { validator_addr: validators[1].clone(), @@ -874,8 +913,11 @@ mod test_apply_bp_roots_to_storage { .sig, } .sign(&keys[&validators[1]].protocol); - _ = apply_derived_tx(&mut state, vext.into()) - .expect("Test failed"); + _ = apply_derived_tx::<_, _, GovStore<_>>( + &mut state, + vext.into(), + ) + .expect("Test failed"); }; } diff --git a/crates/ethereum_bridge/src/protocol/transactions/ethereum_events/mod.rs b/crates/ethereum_bridge/src/protocol/transactions/ethereum_events/mod.rs index 2f5ebff9543..aeadccc6175 100644 --- a/crates/ethereum_bridge/src/protocol/transactions/ethereum_events/mod.rs +++ b/crates/ethereum_bridge/src/protocol/transactions/ethereum_events/mod.rs @@ -14,9 +14,10 @@ use namada_core::ethereum_events::EthereumEvent; use namada_core::key::common; use namada_core::storage::{BlockHeight, Epoch, Key}; use namada_core::token::Amount; -use namada_proof_of_stake::pos_queries::PosQueries; +use namada_proof_of_stake::storage::read_owned_pos_params; use namada_state::tx_queue::ExpiredTx; use namada_state::{DBIter, StorageHasher, WlState, DB}; +use namada_systems::governance; use namada_tx::data::BatchedTxResult; use namada_vote_ext::ethereum_events::{MultiSignedEthEvent, SignedVext, Vext}; @@ -81,15 +82,16 @@ where /// /// This function is deterministic based on some existing blockchain state and /// the passed `events`. -pub fn apply_derived_tx( +pub fn apply_derived_tx( state: &mut WlState, events: Vec, ) -> Result where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, + Gov: governance::Read>, { - let mut changed_keys = timeout_events(state)?; + let mut changed_keys = timeout_events::(state)?; if events.is_empty() { return Ok(BatchedTxResult { changed_keys, @@ -116,7 +118,7 @@ where let voting_powers = utils::get_voting_powers(state, &updates)?; let (mut apply_updates_keys, eth_bridge_events) = - apply_updates(state, updates, voting_powers)?; + apply_updates::(state, updates, voting_powers)?; changed_keys.append(&mut apply_updates_keys); Ok(BatchedTxResult { @@ -134,7 +136,7 @@ where /// /// The `voting_powers` map must contain a voting power for all /// `(Address, BlockHeight)`s that occur in any of the `updates`. -pub(super) fn apply_updates( +pub(super) fn apply_updates( state: &mut WlState, updates: HashSet, voting_powers: HashMap<(Address, BlockHeight), Amount>, @@ -142,6 +144,7 @@ pub(super) fn apply_updates( where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, + Gov: governance::Read>, { tracing::debug!( updates.len = updates.len(), @@ -156,7 +159,7 @@ where // The order in which updates are applied to storage does not matter. // The final storage state will be the same regardless. let (mut changed, newly_confirmed) = - apply_update(state, update.clone(), &voting_powers)?; + apply_update::(state, update.clone(), &voting_powers)?; changed_keys.append(&mut changed); if newly_confirmed { confirmed.push(update.body); @@ -183,7 +186,7 @@ where /// /// The `voting_powers` map must contain a voting power for all /// `(Address, BlockHeight)`s that occur in `update`. -fn apply_update( +fn apply_update( state: &mut WlState, update: EthMsgUpdate, voting_powers: &HashMap<(Address, BlockHeight), Amount>, @@ -191,6 +194,7 @@ fn apply_update( where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, + Gov: governance::Read>, { let eth_msg_keys = vote_tallies::Keys::from(&update.body); let exists_in_storage = if let Some(seen) = @@ -208,8 +212,11 @@ where let (vote_tracking, changed, confirmed, already_present) = if !exists_in_storage { tracing::debug!(%eth_msg_keys.prefix, "Ethereum event not seen before by any validator"); - let vote_tracking = - calculate_new(state, update.seen_by, voting_powers)?; + let vote_tracking = calculate_new::( + state, + update.seen_by, + voting_powers, + )?; let changed = eth_msg_keys.into_iter().collect(); let confirmed = vote_tracking.seen; (vote_tracking, changed, confirmed, false) @@ -221,7 +228,11 @@ where let new_votes = NewVotes::new(update.seen_by.clone(), voting_powers)?; let (vote_tracking, changed) = - votes::update::calculate(state, ð_msg_keys, new_votes)?; + votes::update::calculate::( + state, + ð_msg_keys, + new_votes, + )?; if changed.is_empty() { return Ok((changed, false)); } @@ -241,10 +252,11 @@ where Ok((changed, confirmed)) } -fn timeout_events(state: &mut WlState) -> Result +fn timeout_events(state: &mut WlState) -> Result where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, + Gov: governance::Read>, { let mut changed = ChangedKeys::new(); for keys in get_timed_out_eth_events(state)? { @@ -252,7 +264,9 @@ where %keys.prefix, "Ethereum event timed out", ); - if let Some(event) = votes::storage::delete(state, &keys)? { + if let Some(event) = + votes::storage::delete::(state, &keys)? + { tracing::debug!( %keys.prefix, "Queueing Ethereum event for retransmission", @@ -281,7 +295,7 @@ where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, { - let unbonding_len = state.pos_queries().get_pos_params().unbonding_len; + let unbonding_len = read_owned_pos_params(state)?.unbonding_len; let current_epoch = state.in_mem().last_epoch; if current_epoch.0 <= unbonding_len { return Ok(Vec::new()); @@ -358,7 +372,7 @@ mod tests { EpochedVotingPower, EpochedVotingPowerExt, Votes, }; use crate::storage::wrapped_erc20s; - use crate::test_utils; + use crate::test_utils::{self, GovStore}; use crate::token::storage_key::{balance_key, minted_balance_key}; /// All kinds of [`Keys`]. @@ -407,8 +421,11 @@ mod tests { )], ); - let (changed_keys, _) = - apply_updates(&mut state, updates, voting_powers)?; + let (changed_keys, _) = apply_updates::<_, _, GovStore<_>>( + &mut state, + updates, + voting_powers, + )?; let eth_msg_keys: vote_tallies::Keys = (&body).into(); let wrapped_erc20_token = wrapped_erc20s::token(&asset); @@ -440,7 +457,7 @@ mod tests { let voting_power = state .read::(ð_msg_keys.voting_power())? .expect("Test failed") - .fractional_stake(&state); + .fractional_stake::<_, _, GovStore<_>>(&state); assert_eq!(voting_power, FractionalVotingPower::WHOLE); let epoch: Epoch = state @@ -492,7 +509,7 @@ mod tests { }], }; - let result = apply_derived_tx( + let result = apply_derived_tx::<_, _, GovStore<_>>( &mut state, vec![MultiSignedEthEvent { event: event.clone(), @@ -548,7 +565,7 @@ mod tests { }], }; - let result = apply_derived_tx( + let result = apply_derived_tx::<_, _, GovStore<_>>( &mut state, vec![MultiSignedEthEvent { event: event.clone(), @@ -607,7 +624,8 @@ mod tests { let multisigneds = vec![multisigned.clone(), multisigned]; - let result = apply_derived_tx(&mut state, multisigneds); + let result = + apply_derived_tx::<_, _, GovStore<_>>(&mut state, multisigneds); let tx_result = match result { Ok(tx_result) => tx_result, Err(err) => panic!("unexpected error: {:#?}", err), @@ -633,7 +651,7 @@ mod tests { let voting_power = state .read::(ð_msg_keys.voting_power())? .expect("Test failed") - .fractional_stake(&state); + .fractional_stake::<_, _, GovStore<_>>(&state); assert_eq!(voting_power, FractionalVotingPower::HALF); Ok(()) @@ -717,7 +735,7 @@ mod tests { receiver: receiver.clone(), }], }; - let _result = apply_derived_tx( + let _result = apply_derived_tx::<_, _, GovStore<_>>( &mut state, vec![MultiSignedEthEvent { event: event.clone(), @@ -731,11 +749,13 @@ mod tests { // commit then update the epoch state.commit_block().unwrap(); - let unbonding_len = - namada_proof_of_stake::storage::read_pos_params(&state) - .expect("Test failed") - .unbonding_len - + 1; + let unbonding_len = namada_proof_of_stake::storage::read_pos_params::< + _, + GovStore<_>, + >(&state) + .expect("Test failed") + .unbonding_len + + 1; state.in_mem_mut().last_epoch = state.in_mem().last_epoch + unbonding_len; state.in_mem_mut().block.epoch = state.in_mem().last_epoch + 1_u64; @@ -748,7 +768,7 @@ mod tests { receiver, }], }; - let result = apply_derived_tx( + let result = apply_derived_tx::<_, _, GovStore<_>>( &mut state, vec![MultiSignedEthEvent { event: new_event.clone(), @@ -853,7 +873,7 @@ mod tests { }; let keys = vote_tallies::Keys::from(&event); - let result = apply_derived_tx( + let result = apply_derived_tx::<_, _, GovStore<_>>( &mut state, vec![MultiSignedEthEvent { event: event.clone(), @@ -866,7 +886,7 @@ mod tests { (KeyKind::VotingPower, Some(power)) => { let power = EpochedVotingPower::try_from_slice(&power) .expect("Test failed") - .fractional_stake(&state); + .fractional_stake::<_, _, GovStore<_>>(&state); assert_eq!(power, FractionalVotingPower::HALF); } (_, Some(_)) => {} @@ -875,16 +895,18 @@ mod tests { // commit then update the epoch state.commit_block().unwrap(); - let unbonding_len = - namada_proof_of_stake::storage::read_pos_params(&state) - .expect("Test failed") - .unbonding_len - + 1; + let unbonding_len = namada_proof_of_stake::storage::read_pos_params::< + _, + GovStore<_>, + >(&state) + .expect("Test failed") + .unbonding_len + + 1; state.in_mem_mut().last_epoch = state.in_mem().last_epoch + unbonding_len; state.in_mem_mut().block.epoch = state.in_mem().last_epoch + 1_u64; - let result = apply_derived_tx( + let result = apply_derived_tx::<_, _, GovStore<_>>( &mut state, vec![MultiSignedEthEvent { event, @@ -897,7 +919,7 @@ mod tests { (KeyKind::VotingPower, Some(power)) => { let power = EpochedVotingPower::try_from_slice(&power) .expect("Test failed") - .fractional_stake(&state); + .fractional_stake::<_, _, GovStore<_>>(&state); assert_eq!(power, FractionalVotingPower::HALF); } (_, Some(_)) => {} @@ -933,8 +955,10 @@ mod tests { macro_rules! nonce_ok { ($nonce:expr) => { let (multisigned, event) = new_multisigned($nonce); - let tx_result = - apply_derived_tx(&mut state, vec![multisigned])?; + let tx_result = apply_derived_tx::<_, _, GovStore<_>>( + &mut state, + vec![multisigned], + )?; let eth_msg_keys = vote_tallies::Keys::from(&event); assert!( @@ -952,8 +976,10 @@ mod tests { macro_rules! nonce_err { ($nonce:expr) => { let (multisigned, event) = new_multisigned($nonce); - let tx_result = - apply_derived_tx(&mut state, vec![multisigned])?; + let tx_result = apply_derived_tx::<_, _, GovStore<_>>( + &mut state, + vec![multisigned], + )?; let eth_msg_keys = vote_tallies::Keys::from(&event); assert!( diff --git a/crates/ethereum_bridge/src/protocol/transactions/utils.rs b/crates/ethereum_bridge/src/protocol/transactions/utils.rs index 7a1b2c11a57..8a012535c5c 100644 --- a/crates/ethereum_bridge/src/protocol/transactions/utils.rs +++ b/crates/ethereum_bridge/src/protocol/transactions/utils.rs @@ -6,9 +6,9 @@ use namada_core::address::Address; use namada_core::collections::{HashMap, HashSet}; use namada_core::storage::BlockHeight; use namada_core::token; -use namada_proof_of_stake::pos_queries::PosQueries; +use namada_proof_of_stake::storage::read_consensus_validator_set_addresses_with_stake; use namada_proof_of_stake::types::WeightedValidator; -use namada_state::{DBIter, StorageHasher, WlState, DB}; +use namada_state::{DBIter, StorageHasher, StorageRead, WlState, DB}; /// Proof of some arbitrary tally whose voters can be queried. pub(super) trait GetVoters { @@ -64,16 +64,13 @@ where { let mut consensus_validators = BTreeMap::default(); for height in block_heights.into_iter() { - let epoch = state.pos_queries().get_epoch(height).expect( + let epoch = state.get_epoch_at_height(height).unwrap().expect( "The epoch of the last block height should always be known", ); _ = consensus_validators.insert( height, - state - .pos_queries() - .get_consensus_validators(Some(epoch)) - .iter() - .collect(), + read_consensus_validator_set_addresses_with_stake(state, epoch) + .unwrap(), ); } consensus_validators diff --git a/crates/ethereum_bridge/src/protocol/transactions/validator_set_update/mod.rs b/crates/ethereum_bridge/src/protocol/transactions/validator_set_update/mod.rs index 07dba2e9df8..c79281e20a8 100644 --- a/crates/ethereum_bridge/src/protocol/transactions/validator_set_update/mod.rs +++ b/crates/ethereum_bridge/src/protocol/transactions/validator_set_update/mod.rs @@ -7,6 +7,7 @@ use namada_core::key::common; use namada_core::storage::{BlockHeight, Epoch}; use namada_core::token::Amount; use namada_state::{DBIter, StorageHasher, WlState, DB}; +use namada_systems::governance; use namada_tx::data::BatchedTxResult; use namada_vote_ext::validator_set_update; @@ -33,7 +34,7 @@ impl utils::GetVoters for (&validator_set_update::VextDigest, BlockHeight) { /// Sign the next set of validators, and return the associated /// vote extension protocol transaction. -pub fn sign_validator_set_update( +pub fn sign_validator_set_update( state: &WlState, validator_addr: &Address, eth_hot_key: &common::SecretKey, @@ -41,6 +42,7 @@ pub fn sign_validator_set_update( where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, + Gov: governance::Read>, { state .ethbridge_queries() @@ -50,8 +52,7 @@ where let voting_powers = state .ethbridge_queries() - .get_consensus_eth_addresses(Some(next_epoch)) - .iter() + .get_consensus_eth_addresses::(next_epoch) .map(|(eth_addr_book, _, voting_power)| { (eth_addr_book, voting_power) }) @@ -68,7 +69,7 @@ where } /// Aggregate validators' votes -pub fn aggregate_votes( +pub fn aggregate_votes( state: &mut WlState, ext: validator_set_update::VextDigest, signing_epoch: Epoch, @@ -76,6 +77,7 @@ pub fn aggregate_votes( where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, + Gov: governance::Read>, { if ext.signatures.is_empty() { tracing::debug!("Ignoring empty validator set update"); @@ -101,7 +103,7 @@ where .next_height(); let voting_powers = utils::get_voting_powers(state, (&ext, epoch_2nd_height))?; - let changed_keys = apply_update( + let changed_keys = apply_update::( state, ext, signing_epoch, @@ -115,7 +117,7 @@ where }) } -fn apply_update( +fn apply_update( state: &mut WlState, ext: validator_set_update::VextDigest, signing_epoch: Epoch, @@ -125,6 +127,7 @@ fn apply_update( where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, + Gov: governance::Read>, { let next_epoch = { // proofs should be written to the sub-key space of the next epoch. @@ -163,8 +166,11 @@ where "Validator set update votes already in storage", ); let new_votes = NewVotes::new(seen_by, &voting_powers)?; - let (tally, changed) = - votes::update::calculate(state, &valset_upd_keys, new_votes)?; + let (tally, changed) = votes::update::calculate::<_, _, Gov, _>( + state, + &valset_upd_keys, + new_votes, + )?; if changed.is_empty() { return Ok(changed); } @@ -175,7 +181,10 @@ where ( state .ethbridge_queries() - .get_eth_addr_book(&addr, Some(signing_epoch)) + .get_eth_addr_book::( + &addr, + Some(signing_epoch), + ) .expect("All validators should have eth keys"), sig, ) @@ -188,14 +197,21 @@ where ?ext.voting_powers, "New validator set update vote aggregation started" ); - let tally = votes::calculate_new(state, seen_by, &voting_powers)?; + let tally = votes::calculate_new::( + state, + seen_by, + &voting_powers, + )?; let mut proof = EthereumProof::new(ext.voting_powers); proof.attach_signature_batch(ext.signatures.into_iter().map( |(addr, sig)| { ( state .ethbridge_queries() - .get_eth_addr_book(&addr, Some(signing_epoch)) + .get_eth_addr_book::( + &addr, + Some(signing_epoch), + ) .expect("All validators should have eth keys"), sig, ) @@ -233,11 +249,14 @@ where mod test_valset_upd_state_changes { use namada_core::address; use namada_core::voting_power::FractionalVotingPower; - use namada_proof_of_stake::pos_queries::PosQueries; + use namada_proof_of_stake::queries::{ + get_total_voting_power, read_validator_stake, + }; + use namada_state::StorageRead; use namada_vote_ext::validator_set_update::VotingPowersMap; use super::*; - use crate::test_utils; + use crate::test_utils::{self, GovStore}; /// Test that if a validator set update becomes "seen", then /// it should have a complete proof backing it up in storage. @@ -247,11 +266,11 @@ mod test_valset_upd_state_changes { let last_height = state.in_mem().get_last_block_height(); let signing_epoch = state - .pos_queries() - .get_epoch(last_height) + .get_epoch_at_height(last_height) + .unwrap() .expect("The epoch of the last block height should be known"); - let tx_result = aggregate_votes( + let tx_result = aggregate_votes::<_, _, GovStore<_>>( &mut state, validator_set_update::VextDigest::singleton( validator_set_update::Vext { @@ -303,7 +322,7 @@ mod test_valset_upd_state_changes { addr_book, state .ethbridge_queries() - .get_eth_addr_book( + .get_eth_addr_book::>( &address::testing::established_address_1(), Some(signing_epoch) ) @@ -312,17 +331,14 @@ mod test_valset_upd_state_changes { // since only one validator is configured, we should // have reached a complete proof - let total_voting_power = state - .pos_queries() - .get_total_voting_power(Some(signing_epoch)); - let validator_voting_power = state - .pos_queries() - .get_validator_from_address( - &address::testing::established_address_1(), - Some(signing_epoch), - ) - .expect("Test failed") - .0; + let total_voting_power = + get_total_voting_power::<_, GovStore<_>>(&state, signing_epoch); + let validator_voting_power = read_validator_stake::<_, GovStore<_>>( + &state, + &address::testing::established_address_1(), + signing_epoch, + ) + .expect("Test failed"); let voting_power = FractionalVotingPower::new( validator_voting_power.into(), total_voting_power.into(), @@ -351,11 +367,11 @@ mod test_valset_upd_state_changes { let last_height = state.in_mem().get_last_block_height(); let signing_epoch = state - .pos_queries() - .get_epoch(last_height) + .get_epoch_at_height(last_height) + .unwrap() .expect("The epoch of the last block height should be known"); - let tx_result = aggregate_votes( + let tx_result = aggregate_votes::<_, _, GovStore<_>>( &mut state, validator_set_update::VextDigest::singleton( validator_set_update::Vext { @@ -407,7 +423,7 @@ mod test_valset_upd_state_changes { addr_book, state .ethbridge_queries() - .get_eth_addr_book( + .get_eth_addr_book::>( &address::testing::established_address_1(), Some(signing_epoch) ) @@ -415,17 +431,14 @@ mod test_valset_upd_state_changes { ); // make sure we do not have a complete proof yet - let total_voting_power = state - .pos_queries() - .get_total_voting_power(Some(signing_epoch)); - let validator_voting_power = state - .pos_queries() - .get_validator_from_address( - &address::testing::established_address_1(), - Some(signing_epoch), - ) - .expect("Test failed") - .0; + let total_voting_power = + get_total_voting_power::<_, GovStore<_>>(&state, signing_epoch); + let validator_voting_power = read_validator_stake::<_, GovStore<_>>( + &state, + &address::testing::established_address_1(), + signing_epoch, + ) + .expect("Test failed"); let voting_power = FractionalVotingPower::new( validator_voting_power.into(), total_voting_power.into(), diff --git a/crates/ethereum_bridge/src/protocol/transactions/votes.rs b/crates/ethereum_bridge/src/protocol/transactions/votes.rs index 87f7805ccd6..6bde8acf138 100644 --- a/crates/ethereum_bridge/src/protocol/transactions/votes.rs +++ b/crates/ethereum_bridge/src/protocol/transactions/votes.rs @@ -13,8 +13,9 @@ use namada_core::voting_power::FractionalVotingPower; use namada_macros::BorshDeserializer; #[cfg(feature = "migrations")] use namada_migrations::*; -use namada_proof_of_stake::pos_queries::PosQueries; -use namada_state::{DBIter, StorageHasher, WlState, DB}; +use namada_proof_of_stake::queries::get_total_voting_power; +use namada_state::{DBIter, StorageHasher, StorageRead, WlState, DB}; +use namada_systems::governance; use super::{read, ChangedKeys}; @@ -37,13 +38,14 @@ pub trait EpochedVotingPowerExt { /// Query the stake of the most secure [`Epoch`] referenced by an /// [`EpochedVotingPower`]. This translates to the [`Epoch`] with /// the most staked tokens. - fn epoch_max_voting_power( + fn epoch_max_voting_power( &self, state: &WlState, ) -> Option where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, - H: 'static + StorageHasher + Sync; + H: 'static + StorageHasher + Sync, + Gov: governance::Read>; /// Fetch the sum of the stake tallied on an /// [`EpochedVotingPower`]. @@ -53,15 +55,18 @@ pub trait EpochedVotingPowerExt { /// [`EpochedVotingPower`], as a fraction over /// the maximum stake seen in the epochs voted on. #[inline] - fn fractional_stake( + fn fractional_stake( &self, state: &WlState, ) -> FractionalVotingPower where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, + Gov: governance::Read>, { - let Some(max_voting_power) = self.epoch_max_voting_power(state) else { + let Some(max_voting_power) = + self.epoch_max_voting_power::<_, _, Gov>(state) + else { return FractionalVotingPower::NULL; }; FractionalVotingPower::new( @@ -74,12 +79,15 @@ pub trait EpochedVotingPowerExt { /// Check if the [`Tally`] associated with an [`EpochedVotingPower`] /// can be considered `seen`. #[inline] - fn has_majority_quorum(&self, state: &WlState) -> bool + fn has_majority_quorum(&self, state: &WlState) -> bool where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, + Gov: governance::Read>, { - let Some(max_voting_power) = self.epoch_max_voting_power(state) else { + let Some(max_voting_power) = + self.epoch_max_voting_power::<_, _, Gov>(state) + else { return false; }; // NB: Preserve the safety property of the Tendermint protocol across @@ -100,19 +108,18 @@ pub trait EpochedVotingPowerExt { } impl EpochedVotingPowerExt for EpochedVotingPower { - fn epoch_max_voting_power( + fn epoch_max_voting_power( &self, state: &WlState, ) -> Option where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, + Gov: governance::Read>, { self.keys() .copied() - .map(|epoch| { - state.pos_queries().get_total_voting_power(Some(epoch)) - }) + .map(|epoch| get_total_voting_power::<_, Gov>(state, epoch)) .max() } @@ -149,7 +156,7 @@ pub struct Tally { /// Calculate a new [`Tally`] based on some validators' fractional voting powers /// as specific block heights -pub fn calculate_new( +pub fn calculate_new( state: &WlState, seen_by: Votes, voting_powers: &HashMap<(Address, BlockHeight), token::Amount>, @@ -157,6 +164,7 @@ pub fn calculate_new( where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, + Gov: governance::Read>, { let mut seen_by_voting_power = EpochedVotingPower::new(); for (validator, block_height) in seen_by.iter() { @@ -165,8 +173,8 @@ where { Some(&voting_power) => { let epoch = state - .pos_queries() - .get_epoch(*block_height) + .get_epoch_at_height(*block_height) + .unwrap() .expect("The queried epoch should be known"); let aggregated = seen_by_voting_power .entry(epoch) @@ -184,7 +192,8 @@ where }; } - let newly_confirmed = seen_by_voting_power.has_majority_quorum(state); + let newly_confirmed = + seen_by_voting_power.has_majority_quorum::(state); Ok(Tally { voting_power: seen_by_voting_power, seen_by, @@ -203,10 +212,12 @@ pub fn dedupe(signers: BTreeSet<(Address, BlockHeight)>) -> Votes { mod tests { use namada_core::address; use namada_proof_of_stake::parameters::OwnedPosParams; - use namada_proof_of_stake::storage::write_pos_params; + use namada_proof_of_stake::storage::{ + read_consensus_validator_set_addresses_with_stake, write_pos_params, + }; use super::*; - use crate::test_utils; + use crate::test_utils::{self, GovStore}; #[test] fn test_dedupe_empty() { @@ -306,7 +317,7 @@ mod tests { FractionalVotingPower::HALF * dummy_validator_stake, )]); assert_eq!( - aggregated.fractional_stake(&dummy_storage), + aggregated.fractional_stake::<_, _, GovStore<_>>(&dummy_storage), FractionalVotingPower::HALF ); } @@ -351,12 +362,14 @@ mod tests { // query validators to make sure they were inserted correctly let query_validators = |epoch: u64| { - state - .pos_queries() - .get_consensus_validators(Some(epoch.into())) - .iter() - .map(|validator| (validator.address, validator.bonded_stake)) - .collect::>() + read_consensus_validator_set_addresses_with_stake( + &state, + epoch.into(), + ) + .unwrap() + .into_iter() + .map(|validator| (validator.address, validator.bonded_stake)) + .collect::>() }; let epoch_0_validators = query_validators(0); let epoch_1_validators = query_validators(1); @@ -365,7 +378,7 @@ mod tests { HashMap::from([(validator_1.clone(), validator_1_stake)]) ); assert_eq!( - state.pos_queries().get_total_voting_power(Some(0.into())), + get_total_voting_power::<_, GovStore<_>>(&state, 0.into()), validator_1_stake, ); assert_eq!( @@ -377,7 +390,7 @@ mod tests { ]) ); assert_eq!( - state.pos_queries().get_total_voting_power(Some(1.into())), + get_total_voting_power::<_, GovStore<_>>(&state, 1.into()), total_stake, ); @@ -387,7 +400,7 @@ mod tests { (1.into(), FractionalVotingPower::ONE_THIRD * total_stake), ]); assert_eq!( - aggregated.fractional_stake(&state), + aggregated.fractional_stake::<_, _, GovStore<_>>(&state), FractionalVotingPower::TWO_THIRDS ); } diff --git a/crates/ethereum_bridge/src/protocol/transactions/votes/storage.rs b/crates/ethereum_bridge/src/protocol/transactions/votes/storage.rs index e6a42677039..3d43cabbc0f 100644 --- a/crates/ethereum_bridge/src/protocol/transactions/votes/storage.rs +++ b/crates/ethereum_bridge/src/protocol/transactions/votes/storage.rs @@ -5,6 +5,7 @@ use namada_core::storage::Key; use namada_core::voting_power::FractionalVotingPower; use namada_state::{DBIter, PrefixIter, StorageHasher, WlState, DB}; use namada_storage::{StorageRead, StorageWrite}; +use namada_systems::governance; use super::{EpochedVotingPower, EpochedVotingPowerExt, Tally, Votes}; use crate::storage::vote_tallies; @@ -39,13 +40,14 @@ where /// type `T` being voted on, in case it has accumulated more than 1/3 /// of fractional voting power behind it. #[must_use = "The storage value returned by this function must be used"] -pub fn delete( +pub fn delete( state: &mut WlState, keys: &vote_tallies::Keys, ) -> Result> where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, + Gov: governance::Read>, T: BorshDeserialize, { let opt_body = { @@ -53,7 +55,7 @@ where super::read::value(state, &keys.voting_power())?; if hints::unlikely( - voting_power.fractional_stake(state) + voting_power.fractional_stake::(state) > FractionalVotingPower::ONE_THIRD, ) { let body: T = super::read::value(state, &keys.body())?; @@ -137,7 +139,7 @@ mod tests { use namada_core::ethereum_events::EthereumEvent; use super::*; - use crate::test_utils; + use crate::test_utils::{self, GovStore}; #[test] fn test_delete_expired_tally() { @@ -166,7 +168,8 @@ mod tests { assert!(write(&mut state, &keys, &event, &tally, false).is_ok()); // delete the tally and check that the body is returned - let opt_body = delete(&mut state, &keys).unwrap(); + let opt_body = + delete::<_, _, GovStore<_>, _>(&mut state, &keys).unwrap(); assert_matches!(opt_body, Some(e) if e == event); // now, we write another tally, with <=1/3 voting power @@ -175,7 +178,8 @@ mod tests { assert!(write(&mut state, &keys, &event, &tally, false).is_ok()); // delete the tally and check that no body is returned - let opt_body = delete(&mut state, &keys).unwrap(); + let opt_body = + delete::<_, _, GovStore<_>, _>(&mut state, &keys).unwrap(); assert_matches!(opt_body, None); } diff --git a/crates/ethereum_bridge/src/protocol/transactions/votes/update.rs b/crates/ethereum_bridge/src/protocol/transactions/votes/update.rs index fa899fbaa68..40820463bf0 100644 --- a/crates/ethereum_bridge/src/protocol/transactions/votes/update.rs +++ b/crates/ethereum_bridge/src/protocol/transactions/votes/update.rs @@ -6,8 +6,8 @@ use namada_core::address::Address; use namada_core::collections::{HashMap, HashSet}; use namada_core::storage::BlockHeight; use namada_core::token; -use namada_proof_of_stake::pos_queries::PosQueries; -use namada_state::{DBIter, StorageHasher, WlState, DB}; +use namada_state::{DBIter, StorageHasher, StorageRead, WlState, DB}; +use namada_systems::governance; use super::{ChangedKeys, EpochedVotingPowerExt, Tally, Votes}; use crate::storage::vote_tallies; @@ -90,7 +90,7 @@ impl IntoIterator for NewVotes { /// would change. If [`Tally`] is already `seen = true` in storage, then no /// votes from `vote_info` should be applied, and the returned changed keys will /// be empty. -pub(in super::super) fn calculate( +pub(in super::super) fn calculate( state: &mut WlState, keys: &vote_tallies::Keys, vote_info: NewVotes, @@ -98,6 +98,7 @@ pub(in super::super) fn calculate( where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, + Gov: governance::Read>, T: BorshDeserialize, { tracing::info!( @@ -119,7 +120,7 @@ where "Ignoring duplicate voter" ); } - let tally_post = apply(state, &tally_pre, vote_info) + let tally_post = apply::(state, &tally_pre, vote_info) .expect("We deduplicated voters already, so this should never error"); let changed_keys = keys_changed(keys, &tally_pre, &tally_post); @@ -147,7 +148,7 @@ where /// Takes an existing [`Tally`] and calculates the new [`Tally`] based on new /// voters from `vote_info`. An error is returned if any validator which /// previously voted is present in `vote_info`. -fn apply( +fn apply( state: &WlState, tally: &Tally, vote_info: NewVotes, @@ -155,6 +156,7 @@ fn apply( where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, + Gov: governance::Read>, { // TODO(namada#1305): remove the clone here let mut voting_power_post = tally.voting_power.clone(); @@ -169,8 +171,8 @@ where )); }; let epoch = state - .pos_queries() - .get_epoch(vote_height) + .get_epoch_at_height(vote_height) + .unwrap() .expect("The queried epoch should be known"); let aggregated = voting_power_post .entry(epoch) @@ -180,7 +182,7 @@ where .ok_or_else(|| eyre!("Aggregated voting power overflow"))?; } - let seen_post = voting_power_post.has_majority_quorum(state); + let seen_post = voting_power_post.has_majority_quorum::(state); Ok(Tally { voting_power: voting_power_post, @@ -221,10 +223,11 @@ mod tests { use self::helpers::{default_event, default_total_stake, TallyParams}; use super::*; use crate::protocol::transactions::votes::{self, EpochedVotingPower}; - use crate::test_utils; + use crate::test_utils::{self, GovStore}; mod helpers { use namada_proof_of_stake::storage::total_consensus_stake_handle; + use test_utils::GovStore; use super::*; @@ -283,7 +286,7 @@ mod tests { > FractionalVotingPower::TWO_THIRDS * total_stake, }; votes::storage::write(state, &keys, event, &tally, false)?; - total_consensus_stake_handle().set( + total_consensus_stake_handle().set::<_, GovStore<_>>( state, total_stake, 0u64.into(), @@ -406,7 +409,7 @@ mod tests { )]); let vote_info = NewVotes::new(votes, &voting_powers)?; - let result = apply(&state, &tally_pre, vote_info); + let result = apply::<_, _, GovStore<_>>(&state, &tally_pre, vote_info); assert!(result.is_err()); Ok(()) @@ -443,7 +446,7 @@ mod tests { let vote_info = NewVotes::new(votes, &voting_powers)?; let (tally_post, changed_keys) = - calculate(&mut state, &keys, vote_info)?; + calculate::<_, _, GovStore<_>, _>(&mut state, &keys, vote_info)?; assert_eq!(tally_post, tally_pre); assert!(changed_keys.is_empty()); @@ -470,7 +473,7 @@ mod tests { let vote_info = NewVotes::new(Votes::default(), &HashMap::default())?; let (tally_post, changed_keys) = - calculate(&mut state, &keys, vote_info)?; + calculate::<_, _, GovStore<_>, _>(&mut state, &keys, vote_info)?; assert_eq!(tally_post, tally_pre); assert!(changed_keys.is_empty()); @@ -507,7 +510,7 @@ mod tests { let vote_info = NewVotes::new(votes, &voting_powers)?; let (tally_post, changed_keys) = - calculate(&mut state, &keys, vote_info)?; + calculate::<_, _, GovStore<_>, _>(&mut state, &keys, vote_info)?; assert_eq!( tally_post, @@ -563,7 +566,7 @@ mod tests { let vote_info = NewVotes::new(votes, &voting_powers)?; let (tally_post, changed_keys) = - calculate(&mut state, &keys, vote_info)?; + calculate::<_, _, GovStore<_>, _>(&mut state, &keys, vote_info)?; assert_eq!( tally_post, diff --git a/crates/ethereum_bridge/src/protocol/validation/bridge_pool_roots.rs b/crates/ethereum_bridge/src/protocol/validation/bridge_pool_roots.rs index da546316568..a237e50959b 100644 --- a/crates/ethereum_bridge/src/protocol/validation/bridge_pool_roots.rs +++ b/crates/ethereum_bridge/src/protocol/validation/bridge_pool_roots.rs @@ -2,8 +2,11 @@ use namada_core::keccak::keccak_hash; use namada_core::storage::BlockHeight; -use namada_proof_of_stake::pos_queries::PosQueries; -use namada_state::{DBIter, StorageHasher, WlState, DB}; +use namada_proof_of_stake::queries::{ + get_validator_eth_hot_key, get_validator_protocol_key, +}; +use namada_state::{DBIter, StorageHasher, StorageRead, WlState, DB}; +use namada_systems::governance; use namada_tx::{SignableEthMessage, Signed}; use namada_vote_ext::bridge_pool_roots; @@ -20,7 +23,7 @@ use crate::storage::eth_bridge_queries::EthBridgeQueries; /// * The validator correctly signed the extension. /// * The validator signed over the correct height inside of the extension. /// * Check that the inner signature is valid. -pub fn validate_bp_roots_vext( +pub fn validate_bp_roots_vext( state: &WlState, ext: &Signed, last_height: BlockHeight, @@ -28,11 +31,12 @@ pub fn validate_bp_roots_vext( where D: 'static + DB + for<'iter> DBIter<'iter>, H: 'static + StorageHasher, + Gov: governance::Read>, { // NOTE: for ABCI++, we should pass // `last_height` here, instead of `ext.data.block_height` let ext_height_epoch = - match state.pos_queries().get_epoch(ext.data.block_height) { + match state.get_epoch_at_height(ext.data.block_height).unwrap() { Some(epoch) => epoch, _ => { tracing::debug!( @@ -71,18 +75,21 @@ where // get the public key associated with this validator let validator = &ext.data.validator_addr; - let (_, pk) = state - .pos_queries() - .get_validator_from_address(validator, Some(ext_height_epoch)) - .map_err(|err| { - tracing::debug!( - ?err, - %validator, - "Could not get public key from Storage for some validator, \ - while validating Bridge pool root's vote extension" - ); - VoteExtensionError::PubKeyNotInStorage - })?; + let pk = get_validator_protocol_key::<_, Gov>( + state, + validator, + ext_height_epoch, + ) + .ok() + .flatten() + .ok_or_else(|| { + tracing::debug!( + %validator, + "Could not get public key from Storage for some validator, \ + while validating Bridge pool root's vote extension" + ); + VoteExtensionError::PubKeyNotInStorage + })?; // verify the signature of the vote extension ext.verify(&pk).map_err(|err| { tracing::debug!( @@ -109,10 +116,11 @@ where keccak_hash([bp_root, nonce].concat()), ext.data.sig.clone(), ); - let pk = state - .pos_queries() - .read_validator_eth_hot_key(validator, Some(ext_height_epoch)) - .expect("A validator should have an Ethereum hot key in storage."); + let pk = + get_validator_eth_hot_key::<_, Gov>(state, validator, ext_height_epoch) + .ok() + .flatten() + .expect("A validator should have an Ethereum hot key in storage."); signed.verify(&pk).map_err(|err| { tracing::debug!( ?err, diff --git a/crates/ethereum_bridge/src/protocol/validation/ethereum_events.rs b/crates/ethereum_bridge/src/protocol/validation/ethereum_events.rs index a51aea1efba..acadffb55cd 100644 --- a/crates/ethereum_bridge/src/protocol/validation/ethereum_events.rs +++ b/crates/ethereum_bridge/src/protocol/validation/ethereum_events.rs @@ -1,8 +1,9 @@ //! Ethereum events validation. use namada_core::storage::BlockHeight; -use namada_proof_of_stake::pos_queries::PosQueries; -use namada_state::{DBIter, StorageHasher, WlState, DB}; +use namada_proof_of_stake::queries::get_validator_protocol_key; +use namada_state::{DBIter, StorageHasher, StorageRead, WlState, DB}; +use namada_systems::governance; use namada_tx::Signed; use namada_vote_ext::ethereum_events; @@ -18,7 +19,7 @@ use crate::storage::eth_bridge_queries::EthBridgeQueries; /// * The validator signed over the correct height inside of the extension. /// * There are no duplicate Ethereum events in this vote extension, and the /// events are sorted in ascending order. -pub fn validate_eth_events_vext( +pub fn validate_eth_events_vext( state: &WlState, ext: &Signed, last_height: BlockHeight, @@ -26,11 +27,12 @@ pub fn validate_eth_events_vext( where D: 'static + DB + for<'iter> DBIter<'iter>, H: 'static + StorageHasher, + Gov: governance::Read>, { // NOTE: for ABCI++, we should pass // `last_height` here, instead of `ext.data.block_height` let ext_height_epoch = - match state.pos_queries().get_epoch(ext.data.block_height) { + match state.get_epoch_at_height(ext.data.block_height).unwrap() { Some(epoch) => epoch, _ => { tracing::debug!( @@ -68,18 +70,21 @@ where validate_eth_events(state, &ext.data)?; // get the public key associated with this validator let validator = &ext.data.validator_addr; - let (_, pk) = state - .pos_queries() - .get_validator_from_address(validator, Some(ext_height_epoch)) - .map_err(|err| { - tracing::debug!( - ?err, - %validator, - "Could not get public key from Storage for some validator, \ - while validating Ethereum events vote extension" - ); - VoteExtensionError::PubKeyNotInStorage - })?; + let pk = get_validator_protocol_key::<_, Gov>( + state, + validator, + ext_height_epoch, + ) + .ok() + .flatten() + .ok_or_else(|| { + tracing::debug!( + %validator, + "Could not get public key from Storage for some validator, \ + while validating Ethereum events vote extension" + ); + VoteExtensionError::PubKeyNotInStorage + })?; // verify the signature of the vote extension ext.verify(&pk).map_err(|err| { tracing::debug!( diff --git a/crates/ethereum_bridge/src/protocol/validation/validator_set_update.rs b/crates/ethereum_bridge/src/protocol/validation/validator_set_update.rs index 035b1576841..9e61d1734f1 100644 --- a/crates/ethereum_bridge/src/protocol/validation/validator_set_update.rs +++ b/crates/ethereum_bridge/src/protocol/validation/validator_set_update.rs @@ -1,8 +1,9 @@ //! Validator set update validation. use namada_core::storage::Epoch; -use namada_proof_of_stake::pos_queries::PosQueries; +use namada_proof_of_stake::queries::get_validator_eth_hot_key; use namada_state::{DBIter, StorageHasher, WlState, DB}; +use namada_systems::governance; use namada_vote_ext::validator_set_update; use super::VoteExtensionError; @@ -28,7 +29,7 @@ use crate::storage::eth_bridge_queries::{ /// of the validators of `signing_epoch + 1`. /// * The voting powers signed over were Ethereum ABI encoded, normalized to /// `2^32`, and sorted in descending order. -pub fn validate_valset_upd_vext( +pub fn validate_valset_upd_vext( state: &WlState, ext: &validator_set_update::SignedVext, last_epoch: Epoch, @@ -36,6 +37,7 @@ pub fn validate_valset_upd_vext( where D: 'static + DB + for<'iter> DBIter<'iter>, H: 'static + StorageHasher, + Gov: governance::Read>, { let signing_epoch = ext.data.signing_epoch; if !is_bridge_comptime_enabled() { @@ -75,10 +77,10 @@ where // verify if the new epoch validators' voting powers in storage match // the voting powers in the vote extension let mut no_local_consensus_eth_addresses = 0; - for (eth_addr_book, namada_addr, namada_power) in state - .ethbridge_queries() - .get_consensus_eth_addresses(Some(signing_epoch.next())) - .iter() + for (eth_addr_book, namada_addr, namada_power) in + state + .ethbridge_queries() + .get_consensus_eth_addresses::(signing_epoch.next()) { let &ext_power = match ext.data.voting_powers.get(ð_addr_book) { Some(voting_power) => voting_power, @@ -117,17 +119,21 @@ where } // get the public key associated with this validator let validator = &ext.data.validator_addr; - let pk = state - .pos_queries() - .read_validator_eth_hot_key(validator, Some(signing_epoch)) - .ok_or_else(|| { - tracing::debug!( - %validator, - "Could not get Ethereum hot key from Storage for some validator, \ - while validating valset upd vote extension" - ); - VoteExtensionError::PubKeyNotInStorage - })?; + let pk = get_validator_eth_hot_key::<_, Gov>( + state, + validator, + signing_epoch, + ) + .ok() + .flatten() + .ok_or_else(|| { + tracing::debug!( + %validator, + "Could not get Ethereum hot key from Storage for some validator, \ + while validating valset upd vote extension" + ); + VoteExtensionError::PubKeyNotInStorage + })?; // verify the signature of the vote extension ext.verify(&pk).map_err(|err| { tracing::debug!( @@ -152,7 +158,7 @@ mod tests { use super::*; use crate::storage::eth_bridge_queries::is_bridge_comptime_enabled; - use crate::test_utils; + use crate::test_utils::{self, GovStore}; /// Test that we reject vote extensions containing a superset of the /// next validator set in storage. @@ -215,7 +221,11 @@ mod tests { } .sign(&keys.get(&validator).expect("Test failed").eth_bridge); - let result = validate_valset_upd_vext(&state, &ext, 0.into()); + let result = validate_valset_upd_vext::<_, _, GovStore<_>>( + &state, + &ext, + 0.into(), + ); assert_matches!( result, Err(VoteExtensionError::ExtraValidatorsInExtension) diff --git a/crates/ethereum_bridge/src/storage/eth_bridge_queries.rs b/crates/ethereum_bridge/src/storage/eth_bridge_queries.rs index da9a2d565dd..0627da86c25 100644 --- a/crates/ethereum_bridge/src/storage/eth_bridge_queries.rs +++ b/crates/ethereum_bridge/src/storage/eth_bridge_queries.rs @@ -14,12 +14,14 @@ use namada_core::{hints, token}; use namada_macros::BorshDeserializer; #[cfg(feature = "migrations")] use namada_migrations::*; -use namada_proof_of_stake::pos_queries::{ConsensusValidators, PosQueries}; +use namada_proof_of_stake::queries::get_total_voting_power; use namada_proof_of_stake::storage::{ + read_consensus_validator_set_addresses_with_stake, read_pos_params, validator_eth_cold_key_handle, validator_eth_hot_key_handle, }; use namada_state::{DBIter, StorageHasher, StoreType, WlState, DB}; use namada_storage::StorageRead; +use namada_systems::governance; use namada_vote_ext::validator_set_update::{ EthAddrBook, ValidatorSetArgs, VotingPowersMap, VotingPowersMapExt, }; @@ -308,14 +310,17 @@ where /// For a given Namada validator, return its corresponding Ethereum bridge /// address. #[inline] - pub fn get_ethbridge_from_namada_addr( + pub fn get_ethbridge_from_namada_addr( self, validator: &Address, epoch: Option, - ) -> Option { + ) -> Option + where + Gov: governance::Read>, + { let epoch = epoch.unwrap_or_else(|| self.state.in_mem().get_current_epoch().0); - let params = self.state.pos_queries().get_pos_params(); + let params = read_pos_params::<_, Gov>(self.state).unwrap(); validator_eth_hot_key_handle(validator) .get(self.state, epoch, ¶ms) .expect("Should be able to read eth hot key from storage") @@ -325,14 +330,17 @@ where /// For a given Namada validator, return its corresponding Ethereum /// governance address. #[inline] - pub fn get_ethgov_from_namada_addr( + pub fn get_ethgov_from_namada_addr( self, validator: &Address, epoch: Option, - ) -> Option { + ) -> Option + where + Gov: governance::Read>, + { let epoch = epoch.unwrap_or_else(|| self.state.in_mem().get_current_epoch().0); - let params = self.state.pos_queries().get_pos_params(); + let params = read_pos_params::<_, Gov>(self.state).unwrap(); validator_eth_cold_key_handle(validator) .get(self.state, epoch, ¶ms) .expect("Should be able to read eth cold key from storage") @@ -342,13 +350,18 @@ where /// For a given Namada validator, return its corresponding Ethereum /// address book. #[inline] - pub fn get_eth_addr_book( + pub fn get_eth_addr_book( self, validator: &Address, epoch: Option, - ) -> Option { - let bridge = self.get_ethbridge_from_namada_addr(validator, epoch)?; - let governance = self.get_ethgov_from_namada_addr(validator, epoch)?; + ) -> Option + where + Gov: governance::Read>, + { + let bridge = + self.get_ethbridge_from_namada_addr::(validator, epoch)?; + let governance = + self.get_ethgov_from_namada_addr::(validator, epoch)?; Some(EthAddrBook { hot_key_addr: bridge, cold_key_addr: governance, @@ -356,50 +369,50 @@ where } /// Extension of - /// [`get_consensus_validators`](namada_proof_of_stake::pos_queries::PosQueriesHook::get_consensus_validators), + /// [`read_consensus_validator_set_addresses_with_stake`](namada_proof_of_stake::pos_queries::storage::read_consensus_validator_set_addresses_with_stake), /// which additionally returns all Ethereum addresses of some validator. #[inline] - pub fn get_consensus_eth_addresses( + pub fn get_consensus_eth_addresses( self, - epoch: Option, - ) -> ConsensusEthAddresses<'db, D, H> { - let epoch = - epoch.unwrap_or_else(|| self.state.in_mem().get_current_epoch().0); - let consensus_validators = self - .state - .pos_queries() - .get_consensus_validators(Some(epoch)); - ConsensusEthAddresses { - state: self.state, - consensus_validators, - epoch, - } + epoch: Epoch, + ) -> impl Iterator + 'db + where + Gov: governance::Read>, + { + read_consensus_validator_set_addresses_with_stake(self.state, epoch) + .unwrap() + .into_iter() + .map(move |validator| { + let eth_addr_book = self + .state + .ethbridge_queries() + .get_eth_addr_book::(&validator.address, Some(epoch)) + .expect("All Namada validators should have Ethereum keys"); + (eth_addr_book, validator.address, validator.bonded_stake) + }) } /// Query a chosen [`ValidatorSetArgs`] at the given [`Epoch`]. /// Also returns a map of each validator's voting power. - fn get_validator_set_args( + fn get_validator_set_args( self, epoch: Option, mut select_validator: F, ) -> (ValidatorSetArgs, VotingPowersMap) where + Gov: governance::Read>, F: FnMut(&EthAddrBook) -> EthAddress, { let epoch = epoch.unwrap_or_else(|| self.state.in_mem().get_current_epoch().0); let voting_powers_map: VotingPowersMap = self - .get_consensus_eth_addresses(Some(epoch)) - .iter() + .get_consensus_eth_addresses::(epoch) .map(|(addr_book, _, power)| (addr_book, power)) .collect(); - let total_power = self - .state - .pos_queries() - .get_total_voting_power(Some(epoch)) - .into(); + let total_power = + get_total_voting_power::<_, Gov>(self.state, epoch).into(); let (validators, voting_powers) = voting_powers_map .get_sorted() .into_iter() @@ -426,11 +439,14 @@ where /// Query the Bridge [`ValidatorSetArgs`] at the given [`Epoch`]. /// Also returns a map of each validator's voting power. #[inline] - pub fn get_bridge_validator_set( + pub fn get_bridge_validator_set( self, epoch: Option, - ) -> (ValidatorSetArgs, VotingPowersMap) { - self.get_validator_set_args( + ) -> (ValidatorSetArgs, VotingPowersMap) + where + Gov: governance::Read>, + { + self.get_validator_set_args::( epoch, |&EthAddrBook { hot_key_addr, .. }| hot_key_addr, ) @@ -439,11 +455,14 @@ where /// Query the Governance [`ValidatorSetArgs`] at the given [`Epoch`]. /// Also returns a map of each validator's voting power. #[inline] - pub fn get_governance_validator_set( + pub fn get_governance_validator_set( self, epoch: Option, - ) -> (ValidatorSetArgs, VotingPowersMap) { - self.get_validator_set_args( + ) -> (ValidatorSetArgs, VotingPowersMap) + where + Gov: governance::Read>, + { + self.get_validator_set_args::( epoch, |&EthAddrBook { cold_key_addr, .. }| cold_key_addr, ) @@ -636,36 +655,3 @@ impl EthAssetMint { !self.erc20_amount.is_zero() } } - -/// A handle to the Ethereum addresses of the set of consensus -/// validators in Namada, at some given epoch. -pub struct ConsensusEthAddresses<'db, D, H> -where - D: 'static + DB + for<'iter> DBIter<'iter>, - H: 'static + StorageHasher, -{ - epoch: Epoch, - state: &'db WlState, - consensus_validators: ConsensusValidators<'db, WlState>, -} - -impl<'db, D, H> ConsensusEthAddresses<'db, D, H> -where - D: 'static + DB + for<'iter> DBIter<'iter>, - H: 'static + StorageHasher, -{ - /// Iterate over the Ethereum addresses of the set of consensus validators - /// in Namada, at some given epoch. - pub fn iter<'this: 'db>( - &'this self, - ) -> impl Iterator + 'db { - self.consensus_validators.iter().map(move |validator| { - let eth_addr_book = self - .state - .ethbridge_queries() - .get_eth_addr_book(&validator.address, Some(self.epoch)) - .expect("All Namada validators should have Ethereum keys"); - (eth_addr_book, validator.address, validator.bonded_stake) - }) - } -} diff --git a/crates/ethereum_bridge/src/test_utils.rs b/crates/ethereum_bridge/src/test_utils.rs index f162788a8a9..5301137a248 100644 --- a/crates/ethereum_bridge/src/test_utils.rs +++ b/crates/ethereum_bridge/src/test_utils.rs @@ -13,9 +13,7 @@ use namada_core::ethereum_events::EthAddress; use namada_core::keccak::KeccakHash; use namada_core::key::{self, RefTo}; use namada_core::storage::{BlockHeight, Key}; -use namada_core::token; use namada_proof_of_stake::parameters::OwnedPosParams; -use namada_proof_of_stake::pos_queries::PosQueries; use namada_proof_of_stake::types::GenesisValidator; use namada_proof_of_stake::{ become_validator, bond_tokens, compute_and_store_total_consensus_stake, @@ -23,6 +21,7 @@ use namada_proof_of_stake::{ }; use namada_state::testing::TestState; use namada_storage::{StorageRead, StorageWrite}; +use namada_trans_token as token; use namada_trans_token::credit_tokens; use crate::storage::bridge_pool::get_key_from_hash; @@ -215,7 +214,12 @@ pub fn init_storage_with_validators( }) .collect(); - namada_proof_of_stake::test_utils::test_init_genesis( + namada_proof_of_stake::test_utils::test_init_genesis::< + _, + namada_parameters::Store<_>, + namada_governance::Store<_>, + namada_trans_token::Store<_>, + >( state, OwnedPosParams::default(), validators.into_iter(), @@ -263,7 +267,11 @@ pub fn append_validators_to_storage( let current_epoch = state.in_mem().get_current_epoch().0; let mut all_keys = HashMap::new(); - let params = state.pos_queries().get_pos_params(); + let params = namada_proof_of_stake::storage::read_pos_params::< + _, + namada_governance::Store<_>, + >(state) + .expect("Should be able to read PosParams from storage"); let staking_token = staking_token_address(state); @@ -275,7 +283,7 @@ pub fn append_validators_to_storage( let eth_cold_key = &keys.eth_gov.ref_to(); let eth_hot_key = &keys.eth_bridge.ref_to(); - become_validator( + become_validator::<_, GovStore<_>>( state, BecomeValidator { params: ¶ms, @@ -294,13 +302,20 @@ pub fn append_validators_to_storage( .expect("Test failed"); credit_tokens(state, &staking_token, &validator, stake) .expect("Test failed"); - bond_tokens(state, None, &validator, stake, current_epoch, None) - .expect("Test failed"); + bond_tokens::<_, GovStore<_>, token::Store<_>>( + state, + None, + &validator, + stake, + current_epoch, + None, + ) + .expect("Test failed"); all_keys.insert(validator, keys); } - compute_and_store_total_consensus_stake( + compute_and_store_total_consensus_stake::<_, GovStore<_>>( state, current_epoch + params.pipeline_len, ) @@ -316,3 +331,6 @@ pub fn append_validators_to_storage( all_keys } + +/// Gov impl type +pub type GovStore = namada_governance::Store; diff --git a/crates/ethereum_bridge/src/vp/bridge_pool_vp.rs b/crates/ethereum_bridge/src/vp/bridge_pool_vp.rs index 2413b635c72..9f56970cd56 100644 --- a/crates/ethereum_bridge/src/vp/bridge_pool_vp.rs +++ b/crates/ethereum_bridge/src/vp/bridge_pool_vp.rs @@ -67,7 +67,6 @@ impl AmountDelta { pub struct BridgePool<'ctx, S, CA, EVAL, TokenKeys> where S: 'static + StateRead, - EVAL: 'static + VpEvaluator<'ctx, S, CA, EVAL>, { /// Context to interact with the host structures. pub ctx: Ctx<'ctx, S, CA, EVAL>, diff --git a/crates/ethereum_bridge/src/vp/eth_bridge_vp.rs b/crates/ethereum_bridge/src/vp/eth_bridge_vp.rs index aae9f14bb87..421420376b3 100644 --- a/crates/ethereum_bridge/src/vp/eth_bridge_vp.rs +++ b/crates/ethereum_bridge/src/vp/eth_bridge_vp.rs @@ -24,7 +24,6 @@ pub struct Error(#[from] native_vp::Error); pub struct EthBridge<'ctx, S, CA, EVAL, TokenKeys> where S: 'static + StateRead, - EVAL: 'static + VpEvaluator<'ctx, S, CA, EVAL>, { /// Context to interact with the host structures. pub ctx: Ctx<'ctx, S, CA, EVAL>, diff --git a/crates/ethereum_bridge/src/vp/nut_vp.rs b/crates/ethereum_bridge/src/vp/nut_vp.rs index 8ac7155f356..bfeb65ec2b4 100644 --- a/crates/ethereum_bridge/src/vp/nut_vp.rs +++ b/crates/ethereum_bridge/src/vp/nut_vp.rs @@ -24,7 +24,6 @@ pub struct Error(#[from] native_vp::Error); pub struct NonUsableTokens<'ctx, S, CA, EVAL, TokenKeys> where S: 'static + StateRead, - EVAL: 'static + VpEvaluator<'ctx, S, CA, EVAL>, { /// Context to interact with the host structures. pub ctx: Ctx<'ctx, S, CA, EVAL>, diff --git a/crates/governance/Cargo.toml b/crates/governance/Cargo.toml index 7a3dfa45704..b3f7d33a186 100644 --- a/crates/governance/Cargo.toml +++ b/crates/governance/Cargo.toml @@ -45,6 +45,7 @@ tracing.workspace = true [dev-dependencies] namada_core = { path = "../core", default-features = false, features = ["testing"] } namada_gas = { path = "../gas" } +namada_parameters = { path = "../parameters" } namada_proof_of_stake = { path = "../proof_of_stake", features = ["testing"] } namada_state = { path = "../state", features = ["testing"] } namada_token = { path = "../token", features = ["testing"] } diff --git a/crates/governance/src/lib.rs b/crates/governance/src/lib.rs index 293515dc178..a97a02c536c 100644 --- a/crates/governance/src/lib.rs +++ b/crates/governance/src/lib.rs @@ -34,8 +34,9 @@ pub mod storage; pub mod utils; pub mod vp; -use namada_state::StorageRead; +use namada_state::{StorageRead, StorageWrite}; pub use namada_systems::governance::*; +use parameters::GovernanceParameters; pub use storage::proposal::{InitProposalData, ProposalType, VoteProposalData}; pub use storage::vote::ProposalVote; pub use storage::{init_proposal, is_proposal_accepted, vote_proposal}; @@ -54,4 +55,18 @@ where fn is_proposal_accepted(storage: &S, tx_data: &[u8]) -> Result { storage::is_proposal_accepted(storage, tx_data) } + + fn max_proposal_period(storage: &S) -> Result { + storage::get_max_proposal_period(storage) + } +} + +impl Write for Store +where + S: StorageRead + StorageWrite, +{ + fn init_default_params(storage: &mut S) -> Result<()> { + let params = GovernanceParameters::default(); + params.init_storage(storage) + } } diff --git a/crates/governance/src/storage/proposal.rs b/crates/governance/src/storage/proposal.rs index b7bad04bed5..c5351997502 100644 --- a/crates/governance/src/storage/proposal.rs +++ b/crates/governance/src/storage/proposal.rs @@ -5,7 +5,7 @@ use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use itertools::Itertools; use namada_core::address::Address; use namada_core::hash::Hash; -use namada_core::ibc::core::host::types::identifiers::{ChannelId, PortId}; +pub use namada_core::ibc::PGFIbcTarget; use namada_core::storage::Epoch; use namada_core::token; use namada_macros::BorshDeserializer; @@ -326,95 +326,6 @@ pub struct PGFInternalTarget { pub amount: token::Amount, } -/// The target of a PGF payment -#[derive( - Debug, - Clone, - PartialEq, - Serialize, - Deserialize, - Ord, - Eq, - PartialOrd, - BorshDeserializer, - Hash, -)] -pub struct PGFIbcTarget { - /// The target address on the target chain - pub target: String, - /// The amount of token to fund the target address - pub amount: token::Amount, - /// Port ID to fund - pub port_id: PortId, - /// Channel ID to fund - pub channel_id: ChannelId, -} - -impl BorshSerialize for PGFIbcTarget { - fn serialize( - &self, - writer: &mut W, - ) -> std::io::Result<()> { - BorshSerialize::serialize(&self.target, writer)?; - BorshSerialize::serialize(&self.amount, writer)?; - BorshSerialize::serialize(&self.port_id.to_string(), writer)?; - BorshSerialize::serialize(&self.channel_id.to_string(), writer) - } -} - -impl borsh::BorshDeserialize for PGFIbcTarget { - fn deserialize_reader( - reader: &mut R, - ) -> std::io::Result { - use std::io::{Error, ErrorKind}; - let target: String = BorshDeserialize::deserialize_reader(reader)?; - let amount: token::Amount = - BorshDeserialize::deserialize_reader(reader)?; - let port_id: String = BorshDeserialize::deserialize_reader(reader)?; - let port_id: PortId = port_id.parse().map_err(|err| { - Error::new( - ErrorKind::InvalidData, - format!("Error decoding port ID: {}", err), - ) - })?; - let channel_id: String = BorshDeserialize::deserialize_reader(reader)?; - let channel_id: ChannelId = channel_id.parse().map_err(|err| { - Error::new( - ErrorKind::InvalidData, - format!("Error decoding channel ID: {}", err), - ) - })?; - Ok(Self { - target, - amount, - port_id, - channel_id, - }) - } -} - -impl borsh::BorshSchema for PGFIbcTarget { - fn add_definitions_recursively( - definitions: &mut BTreeMap< - borsh::schema::Declaration, - borsh::schema::Definition, - >, - ) { - let fields = borsh::schema::Fields::NamedFields(vec![ - ("target".into(), String::declaration()), - ("amount".into(), token::Amount::declaration()), - ("port_id".into(), String::declaration()), - ("channel_id".into(), String::declaration()), - ]); - let definition = borsh::schema::Definition::Struct { fields }; - definitions.insert(Self::declaration(), definition); - } - - fn declaration() -> borsh::schema::Declaration { - std::any::type_name::().into() - } -} - /// The actions that a PGF Steward can propose to execute #[derive( Debug, @@ -659,6 +570,7 @@ impl Display for StorageProposal { pub mod testing { use namada_core::address::testing::arb_non_internal_address; use namada_core::hash::testing::arb_hash; + use namada_core::ibc::core::host::types::identifiers::{ChannelId, PortId}; use namada_core::storage::testing::arb_epoch; use namada_core::token::testing::arb_amount; use proptest::prelude::*; diff --git a/crates/governance/src/vp/mod.rs b/crates/governance/src/vp/mod.rs index 5510eb83fc7..5c660b85da5 100644 --- a/crates/governance/src/vp/mod.rs +++ b/crates/governance/src/vp/mod.rs @@ -52,7 +52,6 @@ pub enum Error { pub struct GovernanceVp<'ctx, S, CA, EVAL, PoS, TokenKeys> where S: StateRead, - EVAL: VpEvaluator<'ctx, S, CA, EVAL>, { /// Context to interact with the host structures. pub ctx: Ctx<'ctx, S, CA, EVAL>, @@ -1239,7 +1238,6 @@ mod test { use namada_core::parameters::Parameters; use namada_core::storage::testing::get_dummy_header; use namada_core::time::DateTimeUtc; - use namada_core::token; use namada_gas::{TxGasMeter, VpGasMeter}; use namada_proof_of_stake::bond_tokens; use namada_proof_of_stake::test_utils::get_dummy_genesis_validator; @@ -1249,6 +1247,7 @@ mod test { BlockHeight, Epoch, FullAccessState, Key, Sha256Hasher, State, StateRead, StorageRead, TxIndex, }; + use namada_token as token; use namada_token::storage_key::balance_key; use namada_tx::action::{Action, GovAction, Write}; use namada_tx::data::TxType; @@ -1282,7 +1281,12 @@ mod test { fn init_storage() -> TestState { let mut state = TestState::default(); - namada_proof_of_stake::test_utils::test_init_genesis( + namada_proof_of_stake::test_utils::test_init_genesis::< + _, + namada_parameters::Store<_>, + crate::Store<_>, + namada_token::Store<_>, + >( &mut state, namada_proof_of_stake::OwnedPosParams::default(), vec![get_dummy_genesis_validator()].into_iter(), @@ -2727,7 +2731,7 @@ mod test { token::Amount::native_whole(1000000), ); - bond_tokens( + bond_tokens::<_, crate::Store<_>, token::Store<_>>( &mut state, Some(&delegator_address), &validator_address, @@ -2873,7 +2877,7 @@ mod test { token::Amount::native_whole(1000000), ); - bond_tokens( + bond_tokens::<_, crate::Store<_>, token::Store<_>>( &mut state, Some(&delegator_address), &validator_address, @@ -3019,7 +3023,7 @@ mod test { token::Amount::native_whole(1000000), ); - bond_tokens( + bond_tokens::<_, crate::Store<_>, token::Store<_>>( &mut state, Some(&delegator_address), &validator_address, diff --git a/crates/governance/src/vp/pgf.rs b/crates/governance/src/vp/pgf.rs index 600a9c69056..0b473ef96aa 100644 --- a/crates/governance/src/vp/pgf.rs +++ b/crates/governance/src/vp/pgf.rs @@ -35,7 +35,6 @@ pub enum Error { pub struct PgfVp<'ctx, S, CA, EVAL> where S: 'static + StateRead, - EVAL: VpEvaluator<'ctx, S, CA, EVAL>, { /// Context to interact with the host structures. pub ctx: Ctx<'ctx, S, CA, EVAL>, diff --git a/crates/ibc/Cargo.toml b/crates/ibc/Cargo.toml index 9beb30b2dc3..53cd38d5688 100644 --- a/crates/ibc/Cargo.toml +++ b/crates/ibc/Cargo.toml @@ -24,14 +24,11 @@ testing = ["namada_core/testing", "ibc-testkit", "proptest"] namada_core = { path = "../core" } namada_events = { path = "../events", default-features = false } namada_gas = { path = "../gas" } -namada_governance = { path = "../governance" } namada_macros = {path = "../macros"} namada_migrations = {path = "../migrations", optional = true} -namada_parameters = { path = "../parameters" } namada_state = { path = "../state" } namada_storage = { path = "../storage" } namada_systems = { path = "../systems" } -namada_token = { path = "../token" } namada_tx = { path = "../tx" } namada_vp = { path = "../vp" } @@ -56,9 +53,11 @@ tracing.workspace = true [dev-dependencies] namada_core = { path = "../core", features = ["testing"] } +namada_governance = { path = "../governance" } namada_parameters = { path = "../parameters", features = ["testing"] } namada_proof_of_stake = { path = "../proof_of_stake", features = ["testing"] } namada_state = { path = "../state", features = ["testing"] } +namada_token = { path = "../token" } namada_tx = { path = "../tx", features = ["testing"] } namada_vm = { path = "../vm", features = ["testing"] } diff --git a/crates/ibc/src/actions.rs b/crates/ibc/src/actions.rs index 3b2ffedad24..e438eea3f20 100644 --- a/crates/ibc/src/actions.rs +++ b/crates/ibc/src/actions.rs @@ -2,24 +2,26 @@ use std::cell::RefCell; use std::collections::BTreeSet; +use std::fmt::Debug; +use std::marker::PhantomData; use std::rc::Rc; +use borsh::BorshDeserialize; use ibc::apps::transfer::types::msgs::transfer::MsgTransfer as IbcMsgTransfer; use ibc::apps::transfer::types::packet::PacketData; use ibc::apps::transfer::types::PrefixedCoin; use ibc::core::channel::types::timeout::TimeoutHeight; use namada_core::address::Address; -use namada_core::borsh::BorshSerializeExt; +use namada_core::borsh::{BorshSerialize, BorshSerializeExt}; +use namada_core::ibc::PGFIbcTarget; use namada_core::tendermint::Time as TmTime; use namada_core::token::Amount; use namada_events::EmitEvents; -use namada_governance::storage::proposal::PGFIbcTarget; -use namada_parameters::read_epoch_duration_parameter; use namada_state::{ Epochs, ResultExt, State, StorageError, StorageRead, StorageResult, StorageWrite, }; -use namada_token as token; +use namada_systems::{parameters, trans_token}; use crate::event::IbcEvent; use crate::{ @@ -29,11 +31,13 @@ use crate::{ /// IBC protocol context #[derive(Debug)] -pub struct IbcProtocolContext<'a, S> { +pub struct IbcProtocolContext<'a, S, Token> { state: &'a mut S, + /// Marker for DI types + _marker: PhantomData, } -impl StorageRead for IbcProtocolContext<'_, S> +impl StorageRead for IbcProtocolContext<'_, S, Token> where S: State, { @@ -96,7 +100,7 @@ where } } -impl StorageWrite for IbcProtocolContext<'_, S> +impl StorageWrite for IbcProtocolContext<'_, S, Token> where S: State, { @@ -113,9 +117,13 @@ where } } -impl IbcStorageContext for IbcProtocolContext<'_, S> +impl IbcStorageContext for IbcProtocolContext<'_, S, Token> where S: State + EmitEvents, + Token: trans_token::Keys + + trans_token::Read + + trans_token::Write + + trans_token::Events, { type Storage = Self; @@ -141,7 +149,7 @@ where token: &Address, amount: Amount, ) -> Result<(), StorageError> { - token::transfer(self.state, token, src, dest, amount) + Token::transfer(self.state, token, src, dest, amount) } /// Mint token @@ -151,7 +159,9 @@ where token: &Address, amount: Amount, ) -> Result<(), StorageError> { - ibc_storage::mint_tokens(self.state, target, token, amount) + ibc_storage::mint_tokens_and_emit_event::<_, Token>( + self.state, target, token, amount, + ) } /// Burn token @@ -161,7 +171,7 @@ where token: &Address, amount: Amount, ) -> Result<(), StorageError> { - ibc_storage::burn_tokens(self.state, target, token, amount) + ibc_storage::burn_tokens::<_, Token>(self.state, target, token, amount) } fn insert_verifier( @@ -176,20 +186,33 @@ where } } -impl IbcCommonContext for IbcProtocolContext<'_, S> where - S: State + EmitEvents +impl IbcCommonContext for IbcProtocolContext<'_, S, Token> +where + S: State + EmitEvents, + Token: trans_token::Keys + + trans_token::Read + + trans_token::Write + + trans_token::Events, { } /// Transfer tokens over IBC -pub fn transfer_over_ibc( - state: &mut S, +pub fn transfer_over_ibc<'a, S, Params, Token, Transfer>( + state: &'a mut S, token: &Address, source: &Address, target: &PGFIbcTarget, ) -> StorageResult<()> where - S: State + EmitEvents, + S: 'a + State + EmitEvents, + Params: parameters::Read< + as IbcStorageContext>::Storage, + >, + Token: trans_token::Keys + + trans_token::Write + + trans_token::Events + + Debug, + Transfer: BorshSerialize + BorshDeserialize, { let token = PrefixedCoin { denom: token.to_string().parse().expect("invalid token"), @@ -201,14 +224,20 @@ where receiver: target.target.clone().into(), memo: String::default().into(), }; + let ctx = IbcProtocolContext { + state, + _marker: PhantomData, + }; + let min_duration = Params::epoch_duration_parameter(&ctx)?.min_duration; #[allow(clippy::arithmetic_side_effects)] - let timeout_timestamp = state + let timeout_timestamp = ctx + .state .in_mem() .header .as_ref() .expect("The header should exist") .time - + read_epoch_duration_parameter(state)?.min_duration; + + min_duration; let timeout_timestamp = TmTime::try_from(timeout_timestamp).into_storage_result()?; let message = IbcMsgTransfer { @@ -218,19 +247,20 @@ where timeout_height_on_b: TimeoutHeight::Never, timeout_timestamp_on_b: timeout_timestamp.into(), }; - let data = MsgTransfer { + let data = MsgTransfer:: { message, transfer: None, } .serialize_to_vec(); - let ctx = IbcProtocolContext { state }; - // Use an empty verifiers set placeholder for validation, this is only // needed in txs and not protocol let verifiers = Rc::new(RefCell::new(BTreeSet::
::new())); - let mut actions = IbcActions::new(Rc::new(RefCell::new(ctx)), verifiers); - actions.execute(&data).into_storage_result()?; + let mut actions = IbcActions::<_, Params, Token>::new( + Rc::new(RefCell::new(ctx)), + verifiers, + ); + actions.execute::(&data).into_storage_result()?; Ok(()) } diff --git a/crates/ibc/src/context/client.rs b/crates/ibc/src/context/client.rs index 5d865f3d5ba..32a7e439356 100644 --- a/crates/ibc/src/context/client.rs +++ b/crates/ibc/src/context/client.rs @@ -12,6 +12,7 @@ use ibc_derive::{IbcClientState, IbcConsensusState}; use ibc_testkit::testapp::ibc::clients::mock::client_state::MockClientState; #[cfg(any(test, feature = "testing"))] use ibc_testkit::testapp::ibc::clients::mock::consensus_state::MockConsensusState; +use namada_systems::parameters; use prost::Message; use super::common::IbcCommonContext; @@ -19,8 +20,8 @@ use super::IbcContext; /// ClientState for light clients #[derive(Clone, Debug, IbcClientState)] -#[validation(IbcContext)] -#[execution(IbcContext)] +#[validation(IbcContext>)] +#[execution(IbcContext>)] pub enum AnyClientState { /// Tendermint client state Tendermint(TmClientState), diff --git a/crates/ibc/src/context/common.rs b/crates/ibc/src/context/common.rs index 152653a797d..659a7be0723 100644 --- a/crates/ibc/src/context/common.rs +++ b/crates/ibc/src/context/common.rs @@ -22,9 +22,9 @@ use ibc::primitives::Timestamp; use namada_core::address::Address; use namada_core::storage::{BlockHeight, Key}; use namada_core::tendermint::Time as TmTime; +use namada_core::token::Amount; use namada_state::{StorageError, StorageRead, StorageWrite}; -use namada_token::storage_key::balance_key; -use namada_token::Amount; +use namada_systems::trans_token; use prost::Message; use super::client::{AnyClientState, AnyConsensusState}; @@ -689,14 +689,17 @@ pub trait IbcCommonContext: IbcStorageContext { } /// Return true if the NFT is owned by the owner - fn is_nft_owned( + fn is_nft_owned( &self, class_id: &PrefixedClassId, token_id: &TokenId, owner: &Address, - ) -> Result { + ) -> Result + where + Token: trans_token::Keys, + { let ibc_token = trace::ibc_token_for_nft(class_id, token_id); - let balance_key = balance_key(&ibc_token, owner); + let balance_key = Token::balance_key(&ibc_token, owner); let amount = self.storage().read::(&balance_key)?; Ok(amount == Some(Amount::from_u64(1))) } diff --git a/crates/ibc/src/context/execution.rs b/crates/ibc/src/context/execution.rs index c081d519f73..1701261dec9 100644 --- a/crates/ibc/src/context/execution.rs +++ b/crates/ibc/src/context/execution.rs @@ -18,15 +18,17 @@ use ibc::core::host::types::path::{ }; use ibc::core::host::ExecutionContext; use ibc::primitives::Timestamp; +use namada_systems::parameters; use super::client::AnyClientState; use super::common::IbcCommonContext; use super::IbcContext; use crate::storage; -impl ClientExecutionContext for IbcContext +impl ClientExecutionContext for IbcContext where C: IbcCommonContext, + Params: parameters::Read, { type ClientStateMut = AnyClientState; @@ -94,9 +96,10 @@ where } } -impl ExecutionContext for IbcContext +impl ExecutionContext for IbcContext where C: IbcCommonContext, + Params: parameters::Read, { type E = Self; diff --git a/crates/ibc/src/context/mod.rs b/crates/ibc/src/context/mod.rs index 7bba1137b9b..d6e238c6c91 100644 --- a/crates/ibc/src/context/mod.rs +++ b/crates/ibc/src/context/mod.rs @@ -13,6 +13,7 @@ pub mod validation; use std::cell::RefCell; use std::fmt::Debug; +use std::marker::PhantomData; use std::rc::Rc; use std::time::Duration; @@ -23,7 +24,7 @@ use namada_state::merkle_tree::ics23_specs::proof_specs; /// IBC context to handle IBC-related data #[derive(Debug)] -pub struct IbcContext +pub struct IbcContext where C: common::IbcCommonContext, { @@ -31,9 +32,11 @@ where pub inner: Rc>, /// Validation parameters for IBC VP pub validation_params: ValidationParams, + /// Marker for DI types + pub _marker: PhantomData, } -impl IbcContext +impl IbcContext where C: common::IbcCommonContext, { @@ -42,6 +45,7 @@ where Self { inner, validation_params: ValidationParams::default(), + _marker: PhantomData, } } } diff --git a/crates/ibc/src/context/nft_transfer.rs b/crates/ibc/src/context/nft_transfer.rs index e7317ba94ed..a767834d808 100644 --- a/crates/ibc/src/context/nft_transfer.rs +++ b/crates/ibc/src/context/nft_transfer.rs @@ -1,6 +1,7 @@ //! IBC Non-Fungible token transfer context use std::cell::RefCell; +use std::marker::PhantomData; use std::rc::Rc; use ibc::apps::nft_transfer::context::{ @@ -15,26 +16,32 @@ use ibc::core::handler::types::error::ContextError; use ibc::core::host::types::identifiers::{ChannelId, PortId}; use namada_core::address::Address; use namada_core::token::Amount; +use namada_systems::trans_token; use super::common::IbcCommonContext; use crate::{trace, NftClass, NftMetadata, IBC_ESCROW_ADDRESS}; /// NFT transfer context to handle tokens #[derive(Debug)] -pub struct NftTransferContext +pub struct NftTransferContext where C: IbcCommonContext, { inner: Rc>, + _marker: PhantomData, } -impl NftTransferContext +impl NftTransferContext where C: IbcCommonContext, + Token: trans_token::Keys, { /// Make new NFT transfer context pub fn new(inner: Rc>) -> Self { - Self { inner } + Self { + inner, + _marker: PhantomData, + } } /// Update the mint amount of the token @@ -110,9 +117,10 @@ where } } -impl NftTransferValidationContext for NftTransferContext +impl NftTransferValidationContext for NftTransferContext where C: IbcCommonContext, + Token: trans_token::Keys, { type AccountId = Address; type Nft = NftMetadata; @@ -156,11 +164,11 @@ where self.get_nft(class_id, token_id)?; // Check the account owns the NFT - if self - .inner - .borrow() - .is_nft_owned(class_id, token_id, from_account)? - { + if self.inner.borrow().is_nft_owned::( + class_id, + token_id, + from_account, + )? { Ok(()) } else { Err(NftTransferError::Other(format!( @@ -183,7 +191,7 @@ where self.get_nft(class_id, token_id)?; // Check the NFT is escrowed - if self.inner.borrow().is_nft_owned( + if self.inner.borrow().is_nft_owned::( class_id, token_id, &IBC_ESCROW_ADDRESS, @@ -224,7 +232,7 @@ where if self .inner .borrow() - .is_nft_owned(class_id, token_id, account)? + .is_nft_owned::(class_id, token_id, account)? { Ok(()) } else { @@ -270,9 +278,10 @@ where } } -impl NftTransferExecutionContext for NftTransferContext +impl NftTransferExecutionContext for NftTransferContext where C: IbcCommonContext, + Token: trans_token::Keys, { fn create_or_update_class_execute( &self, diff --git a/crates/ibc/src/context/nft_transfer_mod.rs b/crates/ibc/src/context/nft_transfer_mod.rs index 1d940564253..420d80362e4 100644 --- a/crates/ibc/src/context/nft_transfer_mod.rs +++ b/crates/ibc/src/context/nft_transfer_mod.rs @@ -27,6 +27,7 @@ use ibc::core::host::types::identifiers::{ChannelId, ConnectionId, PortId}; use ibc::core::router::module::Module; use ibc::core::router::types::module::{ModuleExtras, ModuleId}; use ibc::primitives::Signer; +use namada_systems::trans_token; use super::common::IbcCommonContext; use super::nft_transfer::NftTransferContext; @@ -34,17 +35,18 @@ use super::transfer_mod::ModuleWrapper; /// IBC module for NFT transfer #[derive(Debug)] -pub struct NftTransferModule +pub struct NftTransferModule where C: IbcCommonContext, { /// IBC actions - pub ctx: NftTransferContext, + pub ctx: NftTransferContext, } -impl NftTransferModule +impl NftTransferModule where C: IbcCommonContext, + Token: trans_token::Keys, { /// Make a new module pub fn new(ctx: Rc>) -> Self { @@ -54,9 +56,10 @@ where } } -impl ModuleWrapper for NftTransferModule +impl ModuleWrapper for NftTransferModule where C: IbcCommonContext + Debug, + Token: trans_token::Keys + Debug, { fn as_module(&self) -> &dyn Module { self @@ -75,9 +78,10 @@ where } } -impl Module for NftTransferModule +impl Module for NftTransferModule where C: IbcCommonContext + Debug, + Token: trans_token::Keys + Debug, { #[allow(clippy::too_many_arguments)] fn on_chan_open_init_validate( diff --git a/crates/ibc/src/context/token_transfer.rs b/crates/ibc/src/context/token_transfer.rs index 7d0ebee13e2..ebfd0acd5b8 100644 --- a/crates/ibc/src/context/token_transfer.rs +++ b/crates/ibc/src/context/token_transfer.rs @@ -13,8 +13,8 @@ use ibc::core::channel::types::error::ChannelError; use ibc::core::handler::types::error::ContextError; use ibc::core::host::types::identifiers::{ChannelId, PortId}; use namada_core::address::{Address, InternalAddress}; +use namada_core::token::Amount; use namada_core::uint::Uint; -use namada_token::Amount; use super::common::IbcCommonContext; use crate::{trace, IBC_ESCROW_ADDRESS}; diff --git a/crates/ibc/src/context/validation.rs b/crates/ibc/src/context/validation.rs index d5cf6d8068a..be9aad20d50 100644 --- a/crates/ibc/src/context/validation.rs +++ b/crates/ibc/src/context/validation.rs @@ -27,6 +27,7 @@ use ibc::primitives::{Signer, Timestamp}; #[cfg(any(test, feature = "testing"))] use ibc_testkit::testapp::ibc::clients::mock::client_state::MockClientState; use namada_state::StorageRead; +use namada_systems::parameters; use super::client::{AnyClientState, AnyConsensusState}; use super::common::IbcCommonContext; @@ -35,9 +36,10 @@ use crate::storage; const COMMITMENT_PREFIX: &[u8] = b"ibc"; -impl ExtClientValidationContext for IbcContext +impl ExtClientValidationContext for IbcContext where C: IbcCommonContext, + Params: parameters::Read, { fn host_timestamp(&self) -> Result { ValidationContext::host_timestamp(self) @@ -74,9 +76,10 @@ where #[cfg(any(test, feature = "testing"))] use ibc_testkit::testapp::ibc::clients::mock::client_state::MockClientContext; #[cfg(any(test, feature = "testing"))] -impl MockClientContext for IbcContext +impl MockClientContext for IbcContext where C: IbcCommonContext, + Params: parameters::Read<::Storage>, { fn host_timestamp(&self) -> Result { ValidationContext::host_timestamp(self) @@ -87,9 +90,10 @@ where } } -impl ClientValidationContext for IbcContext +impl ClientValidationContext for IbcContext where C: IbcCommonContext, + Params: parameters::Read, { type ClientStateRef = AnyClientState; type ConsensusStateRef = AnyConsensusState; @@ -123,9 +127,10 @@ where } } -impl ValidationContext for IbcContext +impl ValidationContext for IbcContext where C: IbcCommonContext, + Params: parameters::Read, { type HostClientState = AnyClientState; type HostConsensusState = AnyConsensusState; @@ -271,15 +276,14 @@ where .get_block_height() .expect("The height should exist"); - let estimate = - namada_parameters::estimate_max_block_time_from_blocks_and_params( - self.inner.borrow().storage(), - height, - // NB: estimate max height with up to 5 blocks in the past, - // which will not result in too many reads - 5, - ) - .expect("Failed to estimate max block time"); + let estimate = Params::estimate_max_block_time_from_blocks_and_params( + self.inner.borrow().storage(), + height, + // NB: estimate max height with up to 5 blocks in the past, + // which will not result in too many reads + 5, + ) + .expect("Failed to estimate max block time"); // NB: pick a lower max blocktime estimate during tests, // to avoid flakes in CI @@ -298,7 +302,7 @@ where } } -impl ValidateSelfClientContext for IbcContext +impl ValidateSelfClientContext for IbcContext where C: IbcCommonContext, { diff --git a/crates/ibc/src/lib.rs b/crates/ibc/src/lib.rs index a6ba6242ed5..e9e5ae81c3c 100644 --- a/crates/ibc/src/lib.rs +++ b/crates/ibc/src/lib.rs @@ -88,6 +88,7 @@ use namada_core::ibc::core::channel::types::commitment::{ }; pub use namada_core::ibc::*; use namada_core::masp::{addr_taddr, ibc_taddr, TAddrData}; +use namada_core::masp_primitives::transaction::components::ValueSum; use namada_core::token::Amount; use namada_events::EmitEvents; use namada_state::{ @@ -95,8 +96,7 @@ use namada_state::{ StorageWrite, WlState, DB, }; use namada_systems::ibc::ChangedBalances; -use namada_token::transaction::components::ValueSum; -use namada_token::Transfer; +use namada_systems::trans_token; pub use nft::*; use primitives::Timestamp; use prost::Message; @@ -217,11 +217,13 @@ impl namada_systems::ibc::Read for Store where S: StorageRead, { - fn try_extract_masp_tx_from_envelope( + fn try_extract_masp_tx_from_envelope( tx_data: &[u8], ) -> namada_storage::Result> { - let msg = decode_message(tx_data).into_storage_result().ok(); + let msg = decode_message::(tx_data) + .into_storage_result() + .ok(); let tx = if let Some(IbcMessage::Envelope(ref envelope)) = msg { Some(extract_masp_tx_from_envelope(envelope).ok_or_else(|| { namada_storage::Error::new_const( @@ -234,13 +236,15 @@ where Ok(tx) } - fn apply_ibc_packet( + fn apply_ibc_packet( storage: &S, tx_data: &[u8], mut accum: ChangedBalances, keys_changed: &BTreeSet, ) -> namada_storage::Result { - let msg = decode_message(tx_data).into_storage_result().ok(); + let msg = decode_message::(tx_data) + .into_storage_result() + .ok(); match msg { None => {} // This event is emitted on the sender @@ -540,18 +544,21 @@ where /// IBC actions to handle IBC operations #[derive(Debug)] -pub struct IbcActions<'a, C> +pub struct IbcActions<'a, C, Params, Token> where C: IbcCommonContext, { - ctx: IbcContext, + ctx: IbcContext, router: IbcRouter<'a>, verifiers: Rc>>, + _marker: PhantomData, } -impl<'a, C> IbcActions<'a, C> +impl<'a, C, Params, Token> IbcActions<'a, C, Params, Token> where - C: IbcCommonContext + Debug, + C: IbcCommonContext, + Params: namada_systems::parameters::Read, + Token: trans_token::Keys, { /// Make new IBC actions pub fn new( @@ -562,6 +569,7 @@ where ctx: IbcContext::new(ctx), router: IbcRouter::new(), verifiers, + _marker: PhantomData, } } @@ -576,12 +584,12 @@ where } /// Execute according to the message in an IBC transaction or VP - pub fn execute( + pub fn execute( &mut self, tx_data: &[u8], ) -> Result<(Option, Option), Error> { - let message = decode_message(tx_data)?; - match &message { + let message = decode_message::(tx_data)?; + match message { IbcMessage::Transfer(msg) => { let mut token_transfer_ctx = TokenTransferContext::new( self.ctx.inner.clone(), @@ -591,27 +599,27 @@ where send_transfer_execute( &mut self.ctx, &mut token_transfer_ctx, - msg.message.clone(), + msg.message, ) .map_err(Error::TokenTransfer)?; - Ok((msg.transfer.clone(), None)) + Ok((msg.transfer, None)) } IbcMessage::NftTransfer(msg) => { let mut nft_transfer_ctx = - NftTransferContext::new(self.ctx.inner.clone()); + NftTransferContext::<_, Token>::new(self.ctx.inner.clone()); send_nft_transfer_execute( &mut self.ctx, &mut nft_transfer_ctx, - msg.message.clone(), + msg.message, ) .map_err(Error::NftTransfer)?; - Ok((msg.transfer.clone(), None)) + Ok((msg.transfer, None)) } IbcMessage::Envelope(envelope) => { execute(&mut self.ctx, &mut self.router, *envelope.clone()) .map_err(|e| Error::Context(Box::new(e)))?; // Extract MASP tx from the memo in the packet if needed - let masp_tx = match &**envelope { + let masp_tx = match &*envelope { MsgEnvelope::Packet(packet_msg) => { match packet_msg { PacketMsg::Recv(msg) => { @@ -671,12 +679,15 @@ where } /// Validate according to the message in IBC VP - pub fn validate(&self, tx_data: &[u8]) -> Result<(), Error> { + pub fn validate( + &self, + tx_data: &[u8], + ) -> Result<(), Error> { // Use an empty verifiers set placeholder for validation, this is only // needed in actual txs to addresses whose VPs should be triggered let verifiers = Rc::new(RefCell::new(BTreeSet::
::new())); - let message = decode_message(tx_data)?; + let message = decode_message::(tx_data)?; match message { IbcMessage::Transfer(msg) => { let token_transfer_ctx = TokenTransferContext::new( @@ -693,7 +704,7 @@ where } IbcMessage::NftTransfer(msg) => { let nft_transfer_ctx = - NftTransferContext::new(self.ctx.inner.clone()); + NftTransferContext::<_, Token>::new(self.ctx.inner.clone()); send_nft_transfer_validate( &self.ctx, &nft_transfer_ctx, @@ -730,7 +741,9 @@ fn is_ack_successful(ack: &Acknowledgement) -> Result { } /// Tries to decode transaction data to an `IbcMessage` -pub fn decode_message(tx_data: &[u8]) -> Result { +pub fn decode_message( + tx_data: &[u8], +) -> Result, Error> { // ibc-rs message if let Ok(any_msg) = Any::decode(tx_data) { if let Ok(envelope) = MsgEnvelope::try_from(any_msg.clone()) { @@ -741,7 +754,7 @@ pub fn decode_message(tx_data: &[u8]) -> Result { message, transfer: None, }; - return Ok(IbcMessage::Transfer(msg)); + return Ok(IbcMessage::Transfer(Box::new(msg))); } if let Ok(message) = IbcMsgNftTransfer::try_from(any_msg) { let msg = MsgNftTransfer { @@ -753,12 +766,12 @@ pub fn decode_message(tx_data: &[u8]) -> Result { } // Transfer message with `ShieldingTransfer` - if let Ok(msg) = MsgTransfer::try_from_slice(tx_data) { - return Ok(IbcMessage::Transfer(msg)); + if let Ok(msg) = MsgTransfer::::try_from_slice(tx_data) { + return Ok(IbcMessage::Transfer(Box::new(msg))); } // NFT transfer message with `ShieldingTransfer` - if let Ok(msg) = MsgNftTransfer::try_from_slice(tx_data) { + if let Ok(msg) = MsgNftTransfer::::try_from_slice(tx_data) { return Ok(IbcMessage::NftTransfer(msg)); } diff --git a/crates/ibc/src/msg.rs b/crates/ibc/src/msg.rs index b3ae419dca3..44b23fae742 100644 --- a/crates/ibc/src/msg.rs +++ b/crates/ibc/src/msg.rs @@ -16,40 +16,39 @@ use ibc::core::host::types::identifiers::PortId; use ibc::primitives::proto::Protobuf; use masp_primitives::transaction::Transaction as MaspTransaction; use namada_core::borsh::BorshSerializeExt; -use namada_token::Transfer; /// The different variants of an Ibc message #[derive(Debug, Clone)] -pub enum IbcMessage { +pub enum IbcMessage { /// Ibc Envelop Envelope(Box), /// Ibc transaprent transfer - Transfer(MsgTransfer), + Transfer(Box>), /// NFT transfer - NftTransfer(MsgNftTransfer), + NftTransfer(MsgNftTransfer), } /// IBC transfer message with `Transfer` #[derive(Debug, Clone)] -pub struct MsgTransfer { +pub struct MsgTransfer { /// IBC transfer message pub message: IbcMsgTransfer, /// Shieleded transfer for MASP transaction pub transfer: Option, } -impl BorshSerialize for MsgTransfer { +impl BorshSerialize for MsgTransfer { fn serialize( &self, writer: &mut W, ) -> std::io::Result<()> { let encoded_msg = self.message.clone().encode_vec(); - let members = (encoded_msg, self.transfer.clone()); + let members = (encoded_msg, &self.transfer); BorshSerialize::serialize(&members, writer) } } -impl BorshDeserialize for MsgTransfer { +impl BorshDeserialize for MsgTransfer { fn deserialize_reader( reader: &mut R, ) -> std::io::Result { @@ -62,7 +61,7 @@ impl BorshDeserialize for MsgTransfer { } } -impl BorshSchema for MsgTransfer { +impl BorshSchema for MsgTransfer { fn add_definitions_recursively( definitions: &mut BTreeMap, ) { @@ -80,25 +79,25 @@ impl BorshSchema for MsgTransfer { /// IBC NFT transfer message with `Transfer` #[derive(Debug, Clone)] -pub struct MsgNftTransfer { +pub struct MsgNftTransfer { /// IBC NFT transfer message pub message: IbcMsgNftTransfer, /// Shieleded transfer for MASP transaction pub transfer: Option, } -impl BorshSerialize for MsgNftTransfer { +impl BorshSerialize for MsgNftTransfer { fn serialize( &self, writer: &mut W, ) -> std::io::Result<()> { let encoded_msg = self.message.clone().encode_vec(); - let members = (encoded_msg, self.transfer.clone()); + let members = (encoded_msg, &self.transfer); BorshSerialize::serialize(&members, writer) } } -impl BorshDeserialize for MsgNftTransfer { +impl BorshDeserialize for MsgNftTransfer { fn deserialize_reader( reader: &mut R, ) -> std::io::Result { @@ -111,7 +110,7 @@ impl BorshDeserialize for MsgNftTransfer { } } -impl BorshSchema for MsgNftTransfer { +impl BorshSchema for MsgNftTransfer { fn add_definitions_recursively( definitions: &mut BTreeMap, ) { diff --git a/crates/ibc/src/storage.rs b/crates/ibc/src/storage.rs index 1519a5f3e43..d0ff4febd56 100644 --- a/crates/ibc/src/storage.rs +++ b/crates/ibc/src/storage.rs @@ -15,11 +15,9 @@ use ibc::core::host::types::path::{ use namada_core::address::{Address, InternalAddress}; use namada_core::storage::{DbKeySeg, Key, KeySeg}; use namada_core::token::Amount; -use namada_events::extend::UserAccount; -use namada_events::{EmitEvents, EventLevel}; +use namada_events::EmitEvents; use namada_state::{StorageRead, StorageResult, StorageWrite}; -use namada_token as token; -use namada_token::event::{TokenEvent, TokenOperation}; +use namada_systems::trans_token; use thiserror::Error; use crate::event::TOKEN_EVENT_DESCRIPTOR; @@ -54,60 +52,76 @@ pub enum Error { /// IBC storage functions result pub type Result = std::result::Result; +/// Mint IBC tokens. This function doesn't emit event (see +/// `mint_tokens_and_emit_event` below) +pub fn mint_tokens( + storage: &mut S, + target: &Address, + token: &Address, + amount: Amount, +) -> StorageResult<()> +where + S: StorageRead + StorageWrite, + Token: trans_token::Keys + trans_token::Read + trans_token::Write, +{ + Token::credit_tokens(storage, token, target, amount)?; + + let minter_key = Token::minter_key(token); + StorageWrite::write( + storage, + &minter_key, + Address::Internal(InternalAddress::Ibc), + ) +} + /// Mint tokens, and emit an IBC token mint event. -pub fn mint_tokens( - state: &mut S, +pub fn mint_tokens_and_emit_event( + storage: &mut S, target: &Address, token: &Address, amount: Amount, ) -> StorageResult<()> where S: StorageRead + StorageWrite + EmitEvents, + Token: trans_token::Keys + + trans_token::Read + + trans_token::Write + + trans_token::Events, { - token::mint_tokens( - state, - &Address::Internal(InternalAddress::Ibc), + mint_tokens::(storage, target, token, amount)?; + + Token::emit_mint_event( + storage, + TOKEN_EVENT_DESCRIPTOR.into(), token, - target, amount, + target, )?; - state.emit(TokenEvent { - descriptor: TOKEN_EVENT_DESCRIPTOR.into(), - level: EventLevel::Tx, - operation: TokenOperation::Mint { - token: token.clone(), - amount: amount.into(), - post_balance: token::read_balance(state, token, target)?.into(), - target_account: UserAccount::Internal(target.clone()), - }, - }); - Ok(()) } /// Burn tokens, and emit an IBC token burn event. -pub fn burn_tokens( - state: &mut S, +pub fn burn_tokens( + storage: &mut S, target: &Address, token: &Address, amount: Amount, ) -> StorageResult<()> where S: StorageRead + StorageWrite + EmitEvents, + Token: + trans_token::Read + trans_token::Write + trans_token::Events, { - token::burn_tokens(state, token, target, amount)?; - - state.emit(TokenEvent { - descriptor: TOKEN_EVENT_DESCRIPTOR.into(), - level: EventLevel::Tx, - operation: TokenOperation::Burn { - token: token.clone(), - amount: amount.into(), - post_balance: token::read_balance(state, token, target)?.into(), - target_account: UserAccount::Internal(target.clone()), - }, - }); + Token::burn_tokens(storage, token, target, amount)?; + + Token::emit_burn_event( + storage, + TOKEN_EVENT_DESCRIPTOR.into(), + token, + amount, + target, + )?; Ok(()) } diff --git a/crates/ibc/src/vp/context.rs b/crates/ibc/src/vp/context.rs index 38e57ff64ac..1d5f88018e5 100644 --- a/crates/ibc/src/vp/context.rs +++ b/crates/ibc/src/vp/context.rs @@ -3,9 +3,8 @@ use std::collections::BTreeSet; use std::marker::PhantomData; -use namada_core::address::{Address, InternalAddress}; +use namada_core::address::Address; use namada_core::arith::checked; -use namada_core::borsh::BorshSerializeExt; use namada_core::collections::{HashMap, HashSet}; use namada_core::storage::{BlockHeight, Epoch, Epochs, Header, Key, TxIndex}; use namada_events::Event; @@ -20,7 +19,7 @@ use namada_vp::native_vp::{CtxPreStorageRead, VpEvaluator}; use namada_vp::VpEnv; use crate::event::IbcEvent; -use crate::storage::is_ibc_key; +use crate::storage::{self, is_ibc_key}; use crate::{IbcCommonContext, IbcStorageContext}; /// Pseudo execution environment context for ibc native vp @@ -28,7 +27,6 @@ use crate::{IbcCommonContext, IbcStorageContext}; pub struct PseudoExecutionContext<'view, 'a, S, CA, EVAL, Token> where S: 'static + StateRead, - EVAL: VpEvaluator<'a, S, CA, EVAL>, { /// Execution context and storage pub storage: PseudoExecutionStorage<'view, 'a, S, CA, EVAL>, @@ -41,7 +39,6 @@ where pub struct PseudoExecutionStorage<'view, 'a, S, CA, EVAL> where S: 'static + StateRead, - EVAL: VpEvaluator<'a, S, CA, EVAL>, { /// Temporary store for pseudo execution store: HashMap, @@ -247,14 +244,7 @@ where amount: Amount, ) -> Result<()> { let storage = self.storage_mut(); - Token::credit_tokens(storage, token, target, amount)?; - - let minter_key = Token::minter_key(token); - StorageWrite::write( - storage, - &minter_key, - Address::Internal(InternalAddress::Ibc).serialize_to_vec(), - ) + storage::mint_tokens::<_, Token>(storage, target, token, amount) } fn burn_token( diff --git a/crates/ibc/src/vp/mod.rs b/crates/ibc/src/vp/mod.rs index b15bf5854f6..88f657636e6 100644 --- a/crates/ibc/src/vp/mod.rs +++ b/crates/ibc/src/vp/mod.rs @@ -9,6 +9,7 @@ use std::marker::PhantomData; use std::rc::Rc; use std::time::Duration; +use borsh::BorshDeserialize; use context::{ PseudoExecutionContext, PseudoExecutionStorage, VpValidationContext, }; @@ -67,30 +68,77 @@ pub enum Error { pub type VpResult = std::result::Result; /// IBC VP -pub struct Ibc<'ctx, S, CA, EVAL, Params, Gov, Token, PoS> -where +pub struct Ibc< + 'ctx, + S, + CA, + EVAL, + Params, + ParamsPre, + ParamsPseudo, + Gov, + Token, + PoS, + Transfer, +> where S: 'static + StateRead, - EVAL: VpEvaluator<'ctx, S, CA, EVAL>, { /// Context to interact with the host structures. pub ctx: Ctx<'ctx, S, CA, EVAL>, /// Generic types for DI - pub _marker: PhantomData<(Params, Gov, Token, PoS)>, + pub _marker: PhantomData<( + Params, + ParamsPre, + ParamsPseudo, + Gov, + Token, + PoS, + Transfer, + )>, } -impl<'view, 'ctx: 'view, S, CA, EVAL, Params, Gov, Token, PoS> NativeVp<'view> - for Ibc<'ctx, S, CA, EVAL, Params, Gov, Token, PoS> +impl< + 'view, + 'ctx: 'view, + S, + CA, + EVAL, + Params, + ParamsPre, + ParamsPseudo, + Gov, + Token, + PoS, + Transfer, +> NativeVp<'view> + for Ibc< + 'ctx, + S, + CA, + EVAL, + Params, + ParamsPre, + ParamsPseudo, + Gov, + Token, + PoS, + Transfer, + > where S: 'static + StateRead, EVAL: 'static + VpEvaluator<'ctx, S, CA, EVAL> + Debug, CA: 'static + Clone + Debug, Gov: governance::Read>, - Params: parameters::Keys + Params: parameters::Read>, + ParamsPre: parameters::Keys + parameters::Read>, + ParamsPseudo: + parameters::Read>, Token: token::Keys + token::Write> + Debug, PoS: proof_of_stake::Read>, + Transfer: BorshDeserialize, { type Error = Error; @@ -133,18 +181,47 @@ where } } -impl<'view, 'ctx: 'view, S, CA, EVAL, Params, Gov, Token, PoS> - Ibc<'ctx, S, CA, EVAL, Params, Gov, Token, PoS> +impl< + 'view, + 'ctx: 'view, + S, + CA, + EVAL, + Params, + ParamsPre, + ParamsPseudo, + Gov, + Token, + PoS, + Transfer, +> + Ibc< + 'ctx, + S, + CA, + EVAL, + Params, + ParamsPre, + ParamsPseudo, + Gov, + Token, + PoS, + Transfer, + > where S: 'static + StateRead, EVAL: 'static + VpEvaluator<'ctx, S, CA, EVAL> + Debug, CA: 'static + Clone + Debug, - Params: parameters::Keys + Params: parameters::Read>, + ParamsPre: parameters::Keys + parameters::Read>, + ParamsPseudo: + parameters::Read>, Token: token::Keys + token::Write> + Debug, PoS: proof_of_stake::Read>, + Transfer: BorshDeserialize, { /// Instantiate IBC VP pub fn new(ctx: Ctx<'ctx, S, CA, EVAL>) -> Self { @@ -168,16 +245,19 @@ where // needed in actual txs to addresses whose VPs should be triggered let verifiers = Rc::new(RefCell::new(BTreeSet::
::new())); - let mut actions = IbcActions::new(ctx.clone(), verifiers.clone()); + let mut actions = IbcActions::<_, ParamsPseudo, Token>::new( + ctx.clone(), + verifiers.clone(), + ); let module = TransferModule::new(ctx.clone(), verifiers); actions.add_transfer_module(module); - let module = NftTransferModule::new(ctx.clone()); + let module = NftTransferModule::<_, Token>::new(ctx.clone()); actions.add_transfer_module(module); // Charge gas for the expensive execution self.ctx .charge_gas(IBC_ACTION_EXECUTE_GAS) .map_err(Error::NativeVpError)?; - actions.execute(tx_data)?; + actions.execute::(tx_data)?; let changed_ibc_keys: HashSet<&Key> = keys_changed.iter().filter(|k| is_ibc_key(k)).collect(); @@ -223,18 +303,21 @@ where // needed in actual txs to addresses whose VPs should be triggered let verifiers = Rc::new(RefCell::new(BTreeSet::
::new())); - let mut actions = IbcActions::new(ctx.clone(), verifiers.clone()); + let mut actions = + IbcActions::<_, Params, Token>::new(ctx.clone(), verifiers.clone()); actions.set_validation_params(self.validation_params()?); let module = TransferModule::new(ctx.clone(), verifiers); actions.add_transfer_module(module); - let module = NftTransferModule::new(ctx); + let module = NftTransferModule::<_, Token>::new(ctx); actions.add_transfer_module(module); // Charge gas for the expensive validation self.ctx .charge_gas(IBC_ACTION_VALIDATE_GAS) .map_err(Error::NativeVpError)?; - actions.validate(tx_data).map_err(Error::IbcAction) + actions + .validate::(tx_data) + .map_err(Error::IbcAction) } /// Retrieve the validation params @@ -245,8 +328,9 @@ where namada_state::ics23_specs::ibc_proof_specs::<::H>(); let pipeline_len = PoS::pipeline_len(&self.ctx.pre()).map_err(Error::NativeVpError)?; - let epoch_duration = Params::epoch_duration_parameter(&self.ctx.pre()) - .map_err(Error::NativeVpError)?; + let epoch_duration = + ParamsPre::epoch_duration_parameter(&self.ctx.pre()) + .map_err(Error::NativeVpError)?; let unbonding_period_secs = checked!(pipeline_len * epoch_duration.min_duration.0)?; Ok(ValidationParams { @@ -414,6 +498,7 @@ mod tests { use namada_state::testing::TestState; use namada_state::StorageRead; use namada_token::storage_key::balance_key; + use namada_token::Transfer; use namada_tx::data::TxType; use namada_tx::{Authorization, Code, Data, Section, Tx}; use namada_vm::wasm::run::VpEvalWasm; @@ -518,9 +603,15 @@ mod tests { TestState, VpCache, Eval, + namada_parameters::Store< + VpValidationContext<'ctx, 'ctx, TestState, VpCache, Eval>, + >, namada_parameters::Store< CtxPreStorageRead<'ctx, 'ctx, TestState, VpCache, Eval>, >, + namada_parameters::Store< + PseudoExecutionStorage<'ctx, 'ctx, TestState, VpCache, Eval>, + >, namada_governance::Store< CtxPreStorageRead<'ctx, 'ctx, TestState, VpCache, Eval>, >, @@ -530,6 +621,7 @@ mod tests { namada_proof_of_stake::Store< CtxPreStorageRead<'ctx, 'ctx, TestState, VpCache, Eval>, >, + Transfer, >; const ADDRESS: Address = Address::Internal(InternalAddress::Ibc); @@ -553,7 +645,12 @@ mod tests { default_per_epoch_throughput_limit: Amount::native_whole(100), }; ibc_params.init_storage(&mut state).unwrap(); - namada_proof_of_stake::test_utils::test_init_genesis( + namada_proof_of_stake::test_utils::test_init_genesis::< + _, + namada_parameters::Store<_>, + namada_governance::Store<_>, + namada_token::Store<_>, + >( &mut state, namada_proof_of_stake::OwnedPosParams::default(), vec![get_dummy_genesis_validator()].into_iter(), @@ -2268,7 +2365,7 @@ mod tests { let tx_index = TxIndex::default(); let tx_code = vec![]; - let tx_data = MsgTransfer { + let tx_data = MsgTransfer:: { message: msg, transfer: None, } @@ -3127,7 +3224,7 @@ mod tests { let tx_index = TxIndex::default(); let tx_code = vec![]; - let tx_data = MsgNftTransfer { + let tx_data = MsgNftTransfer:: { message: msg, transfer: None, } diff --git a/crates/node/src/bench_utils.rs b/crates/node/src/bench_utils.rs index d03547d0c85..0bfe5273085 100644 --- a/crates/node/src/bench_utils.rs +++ b/crates/node/src/bench_utils.rs @@ -29,7 +29,7 @@ use namada_sdk::events::extend::{ use namada_sdk::events::Event; use namada_sdk::gas::TxGasMeter; use namada_sdk::governance::storage::proposal::ProposalType; -use namada_sdk::governance::InitProposalData; +use namada_sdk::governance::{self, InitProposalData}; use namada_sdk::ibc::apps::transfer::types::msgs::transfer::MsgTransfer as IbcMsgTransfer; use namada_sdk::ibc::apps::transfer::types::packet::PacketData; use namada_sdk::ibc::apps::transfer::types::PrefixedCoin; @@ -234,9 +234,11 @@ impl Default for BenchShell { amount: Amount::native_whole(1000), source: Some(defaults::albert_address()), }; - let params = - proof_of_stake::storage::read_pos_params(&bench_shell.state) - .unwrap(); + let params = proof_of_stake::storage::read_pos_params::< + _, + governance::Store<_>, + >(&bench_shell.state) + .unwrap(); let signed_tx = bench_shell.generate_tx( TX_BOND_WASM, bond, @@ -392,7 +394,7 @@ impl BenchShell { timeout_timestamp_on_b: timeout_timestamp, }; - let msg = MsgTransfer { + let msg = MsgTransfer:: { message, transfer: None, }; @@ -419,9 +421,11 @@ impl BenchShell { } pub fn advance_epoch(&mut self) { - let params = - proof_of_stake::storage::read_pos_params(&self.inner.state) - .unwrap(); + let params = proof_of_stake::storage::read_pos_params::< + _, + governance::Store<_>, + >(&self.inner.state) + .unwrap(); self.state.in_mem_mut().block.epoch = self.state.in_mem().block.epoch.next(); @@ -1248,7 +1252,7 @@ impl BenchShieldedCtx { .get_masp_section(&transfer.shielded_section_hash.unwrap()) .unwrap() .clone(); - let msg = MsgTransfer { + let msg = MsgTransfer:: { message: msg, transfer: Some(transfer), }; diff --git a/crates/node/src/protocol.rs b/crates/node/src/protocol.rs index 5014967b69d..8a905bffdef 100644 --- a/crates/node/src/protocol.rs +++ b/crates/node/src/protocol.rs @@ -980,12 +980,20 @@ where ) => { let ethereum_events::VextDigest { events, .. } = ethereum_events::VextDigest::singleton(ext); - transactions::ethereum_events::apply_derived_tx(state, events) - .map_err(Error::ProtocolTxError) + transactions::ethereum_events::apply_derived_tx::< + _, + _, + governance::Store<_>, + >(state, events) + .map_err(Error::ProtocolTxError) } EthereumTxData::BridgePoolVext(ext) => { - transactions::bridge_pool_roots::apply_derived_tx(state, ext.into()) - .map_err(Error::ProtocolTxError) + transactions::bridge_pool_roots::apply_derived_tx::< + _, + _, + governance::Store<_>, + >(state, ext.into()) + .map_err(Error::ProtocolTxError) } EthereumTxData::ValSetUpdateVext(ext) => { // NOTE(feature = "abcipp"): with ABCI++, we can write the @@ -994,7 +1002,11 @@ where // with ABCI+, multiple vote extension protocol txs may be needed // to reach a complete proof. let signing_epoch = ext.data.signing_epoch; - transactions::validator_set_update::aggregate_votes( + transactions::validator_set_update::aggregate_votes::< + _, + _, + governance::Store<_>, + >( state, validator_set_update::VextDigest::singleton(ext), signing_epoch, diff --git a/crates/node/src/shell/block_alloc.rs b/crates/node/src/shell/block_alloc.rs index ee09fd3ff75..ceabd38565c 100644 --- a/crates/node/src/shell/block_alloc.rs +++ b/crates/node/src/shell/block_alloc.rs @@ -42,7 +42,6 @@ pub mod states; use std::marker::PhantomData; use namada_sdk::parameters; -use namada_sdk::proof_of_stake::pos_queries::PosQueries; use namada_sdk::state::{self, WlState}; #[allow(unused_imports)] @@ -135,7 +134,9 @@ where #[inline] fn from(storage: &WlState) -> Self { Self::init( - storage.pos_queries().get_max_proposal_bytes().get(), + parameters::read_max_proposal_bytes(storage) + .expect("Must be able to read ProposalBytes from storage") + .get(), parameters::get_max_block_gas(storage).unwrap(), ) } diff --git a/crates/node/src/shell/finalize_block.rs b/crates/node/src/shell/finalize_block.rs index 481f448f7b1..2b3ad3fa45d 100644 --- a/crates/node/src/shell/finalize_block.rs +++ b/crates/node/src/shell/finalize_block.rs @@ -28,6 +28,7 @@ use namada_sdk::tx::new_tx_event; use namada_sdk::{ibc, proof_of_stake}; use namada_vote_ext::ethereum_events::MultiSignedEthEvent; use namada_vote_ext::ethereum_tx_data_variants; +use tendermint::abci::types::Misbehavior; use super::*; use crate::facade::tendermint::abci::types::VoteInfo; @@ -107,7 +108,7 @@ where token_finalize_block(&mut self.state, emit_events, is_masp_new_epoch)?; // - PoS // - Must be applied after governance in case it changes PoS params - proof_of_stake::finalize_block( + pos_finalize_block( &mut self.state, emit_events, new_epoch, @@ -291,11 +292,12 @@ where ); // PoS inflation - proof_of_stake::rewards::apply_inflation( - &mut self.state, - last_epoch, - num_blocks_in_last_epoch, - )?; + proof_of_stake::rewards::apply_inflation::< + _, + governance::Store<_>, + parameters::Store<_>, + token::Store<_>, + >(&mut self.state, last_epoch, num_blocks_in_last_epoch)?; // Pgf inflation pgf_apply_inflation(self.state.restrict_writes_to_write_log())?; @@ -1146,14 +1148,43 @@ where ) } +/// Dependency-injection indirection for PoS system +fn pos_finalize_block( + storage: &mut S, + events: &mut impl EmitEvents, + is_new_epoch: bool, + validator_set_update_epoch: Epoch, + votes: Vec, + byzantine_validators: Vec, +) -> StorageResult<()> +where + S: StorageWrite + StorageRead, +{ + proof_of_stake::finalize_block::<_, governance::Store<_>>( + storage, + events, + is_new_epoch, + validator_set_update_epoch, + votes, + byzantine_validators, + ) +} + /// Dependency-injection indirection for PGF inflation fn pgf_apply_inflation(storage: &mut S) -> StorageResult<()> where - S: State + EmitEvents, + S: 'static + State + EmitEvents, { pgf_inflation::apply_inflation::<_, parameters::Store<_>, token::Store<_>, _>( storage, - ibc::transfer_over_ibc, + |state, token, source, target| { + ibc::transfer_over_ibc::< + _, + parameters::Store<_>, + token::Store<_>, + token::Transfer, + >(state, token, source, target) + }, ) } @@ -1226,6 +1257,7 @@ mod test_finalize_block { use namada_test_utils::TestWasms; use namada_vote_ext::ethereum_events; use namada_vp::native_vp::NativeVp; + use proof_of_stake::{bond_tokens, PosParams}; use test_log::test; use super::*; @@ -1887,8 +1919,7 @@ mod test_finalize_block { // Keep applying finalize block let validator = shell.mode.get_validator_address().unwrap(); - let pos_params = - proof_of_stake::storage::read_pos_params(&shell.state).unwrap(); + let pos_params = read_pos_params(&shell.state).unwrap(); let consensus_key = proof_of_stake::storage::validator_consensus_key_handle(validator) .get(&shell.state, Epoch::default(), &pos_params) @@ -2326,35 +2357,39 @@ mod test_finalize_block { total_rewards += inflation; // Query the available rewards - let query_rewards = proof_of_stake::query_reward_tokens( - &shell.state, - None, - &validator.address, - current_epoch, - ) - .unwrap(); + let query_rewards = + proof_of_stake::query_reward_tokens::<_, governance::Store<_>>( + &shell.state, + None, + &validator.address, + current_epoch, + ) + .unwrap(); // Claim the rewards from the initial epoch - let reward_1 = proof_of_stake::claim_reward_tokens( - &mut shell.state, - None, - &validator.address, - current_epoch, - ) - .unwrap(); + let reward_1 = + proof_of_stake::claim_reward_tokens::< + _, + governance::Store<_>, + token::Store<_>, + >( + &mut shell.state, None, &validator.address, current_epoch + ) + .unwrap(); total_claimed += reward_1; assert_eq!(reward_1, query_rewards); assert!(is_reward_equal_enough(total_rewards, total_claimed, 1)); // Query the available rewards again and check that it is 0 now after // the claim - let query_rewards = proof_of_stake::query_reward_tokens( - &shell.state, - None, - &validator.address, - current_epoch, - ) - .unwrap(); + let query_rewards = + proof_of_stake::query_reward_tokens::<_, governance::Store<_>>( + &shell.state, + None, + &validator.address, + current_epoch, + ) + .unwrap(); assert_eq!(query_rewards, token::Amount::zero()); // Try a claim the next block and ensure we get 0 tokens back @@ -2364,11 +2399,12 @@ mod test_finalize_block { votes.clone(), None, ); - let att = proof_of_stake::claim_reward_tokens( - &mut shell.state, - None, - &validator.address, - current_epoch, + let att = proof_of_stake::claim_reward_tokens::< + _, + governance::Store<_>, + token::Store<_>, + >( + &mut shell.state, None, &validator.address, current_epoch ) .unwrap(); assert_eq!(att, token::Amount::zero()); @@ -2380,31 +2416,34 @@ mod test_finalize_block { // Unbond some tokens let unbond_amount = token::Amount::native_whole(50_000); - let unbond_res = proof_of_stake::unbond_tokens( - &mut shell.state, - None, - &validator.address, - unbond_amount, - current_epoch, - false, - ) - .unwrap(); + let unbond_res = + proof_of_stake::unbond_tokens::<_, governance::Store<_>>( + &mut shell.state, + None, + &validator.address, + unbond_amount, + current_epoch, + false, + ) + .unwrap(); assert_eq!(unbond_res.sum, unbond_amount); // Query the available rewards - let query_rewards = proof_of_stake::query_reward_tokens( - &shell.state, - None, - &validator.address, - current_epoch, - ) - .unwrap(); + let query_rewards = + proof_of_stake::query_reward_tokens::<_, governance::Store<_>>( + &shell.state, + None, + &validator.address, + current_epoch, + ) + .unwrap(); - let rew = proof_of_stake::claim_reward_tokens( - &mut shell.state, - None, - &validator.address, - current_epoch, + let rew = proof_of_stake::claim_reward_tokens::< + _, + governance::Store<_>, + token::Store<_>, + >( + &mut shell.state, None, &validator.address, current_epoch ) .unwrap(); total_claimed += rew; @@ -2420,7 +2459,10 @@ mod test_finalize_block { &validator.address, ) .unwrap(); - let bond_amounts = proof_of_stake::bond_amounts_for_rewards( + let bond_amounts = proof_of_stake::bond_amounts_for_rewards::< + _, + governance::Store<_>, + >( &shell.state, &bond_id, last_claim_epoch.unwrap_or_default(), @@ -2460,32 +2502,37 @@ mod test_finalize_block { } // Withdraw tokens - let withdraw_amount = proof_of_stake::withdraw_tokens( - &mut shell.state, - None, - &validator.address, - current_epoch, - ) - .unwrap(); + let withdraw_amount = + proof_of_stake::withdraw_tokens::< + _, + governance::Store<_>, + token::Store<_>, + >( + &mut shell.state, None, &validator.address, current_epoch + ) + .unwrap(); assert_eq!(withdraw_amount, unbond_amount); // Query the available rewards - let query_rewards = proof_of_stake::query_reward_tokens( - &shell.state, - None, - &validator.address, - current_epoch, - ) - .unwrap(); + let query_rewards = + proof_of_stake::query_reward_tokens::<_, governance::Store<_>>( + &shell.state, + None, + &validator.address, + current_epoch, + ) + .unwrap(); // Claim tokens - let reward_2 = proof_of_stake::claim_reward_tokens( - &mut shell.state, - None, - &validator.address, - current_epoch, - ) - .unwrap(); + let reward_2 = + proof_of_stake::claim_reward_tokens::< + _, + governance::Store<_>, + token::Store<_>, + >( + &mut shell.state, None, &validator.address, current_epoch + ) + .unwrap(); total_claimed += reward_2; assert_eq!(query_rewards, reward_2); @@ -2501,13 +2548,14 @@ mod test_finalize_block { assert!(token_diff < token_uncertainty); // Query the available rewards to check that they are 0 - let query_rewards = proof_of_stake::query_reward_tokens( - &shell.state, - None, - &validator.address, - current_epoch, - ) - .unwrap(); + let query_rewards = + proof_of_stake::query_reward_tokens::<_, governance::Store<_>>( + &shell.state, + None, + &validator.address, + current_epoch, + ) + .unwrap(); assert_eq!(query_rewards, token::Amount::zero()); } @@ -2582,7 +2630,7 @@ mod test_finalize_block { ) .unwrap(); let mut current_epoch = shell.state.in_mem().block.epoch; - proof_of_stake::bond_tokens( + bond_tokens::<_, governance::Store<_>, token::Store<_>>( &mut shell.state, Some(&delegator), &validator.address, @@ -2605,13 +2653,15 @@ mod test_finalize_block { } // Claim the rewards for the validator for the first two epochs - let val_reward_1 = proof_of_stake::claim_reward_tokens( - &mut shell.state, - None, - &validator.address, - current_epoch, - ) - .unwrap(); + let val_reward_1 = + proof_of_stake::claim_reward_tokens::< + _, + governance::Store<_>, + token::Store<_>, + >( + &mut shell.state, None, &validator.address, current_epoch + ) + .unwrap(); total_claimed += val_reward_1; assert!(is_reward_equal_enough( total_rewards, @@ -2631,16 +2681,22 @@ mod test_finalize_block { total_rewards += inflation_3; // Claim again for the validator - let val_reward_2 = proof_of_stake::claim_reward_tokens( - &mut shell.state, - None, - &validator.address, - current_epoch, - ) - .unwrap(); + let val_reward_2 = + proof_of_stake::claim_reward_tokens::< + _, + governance::Store<_>, + token::Store<_>, + >( + &mut shell.state, None, &validator.address, current_epoch + ) + .unwrap(); // Claim for the delegator - let del_reward_1 = proof_of_stake::claim_reward_tokens( + let del_reward_1 = proof_of_stake::claim_reward_tokens::< + _, + governance::Store<_>, + token::Store<_>, + >( &mut shell.state, Some(&delegator), &validator.address, @@ -2753,7 +2809,7 @@ mod test_finalize_block { // Validator1 bonds 1 NAM let bond_amount = token::Amount::native_whole(1); - proof_of_stake::bond_tokens( + bond_tokens::<_, governance::Store<_>, token::Store<_>>( &mut shell.state, None, &validator1.address, @@ -2765,7 +2821,7 @@ mod test_finalize_block { // Validator2 changes consensus key let new_ck2 = common_sk_from_simple_seed(1).ref_to(); - proof_of_stake::change_consensus_key( + proof_of_stake::change_consensus_key::<_, governance::Store<_>>( &mut shell.state, &validator2.address, &new_ck2, @@ -2774,7 +2830,7 @@ mod test_finalize_block { .unwrap(); // Validator3 bonds 1 NAM and changes consensus key - proof_of_stake::bond_tokens( + bond_tokens::<_, governance::Store<_>, token::Store<_>>( &mut shell.state, None, &validator3.address, @@ -2784,7 +2840,7 @@ mod test_finalize_block { ) .unwrap(); let new_ck3 = common_sk_from_simple_seed(2).ref_to(); - proof_of_stake::change_consensus_key( + proof_of_stake::change_consensus_key::<_, governance::Store<_>>( &mut shell.state, &validator3.address, &new_ck3, @@ -2834,7 +2890,7 @@ mod test_finalize_block { // Val 1 changes consensus key let new_ck1 = common_sk_from_simple_seed(3).ref_to(); - proof_of_stake::change_consensus_key( + proof_of_stake::change_consensus_key::<_, governance::Store<_>>( &mut shell.state, &validator1.address, &new_ck1, @@ -2843,7 +2899,7 @@ mod test_finalize_block { .unwrap(); // Val 2 is fully unbonded - proof_of_stake::unbond_tokens( + proof_of_stake::unbond_tokens::<_, governance::Store<_>>( &mut shell.state, None, &validator2.address, @@ -2854,7 +2910,7 @@ mod test_finalize_block { .unwrap(); // Val 3 is fully unbonded and changes consensus key - proof_of_stake::unbond_tokens( + proof_of_stake::unbond_tokens::<_, governance::Store<_>>( &mut shell.state, None, &validator3.address, @@ -2864,7 +2920,7 @@ mod test_finalize_block { ) .unwrap(); let new2_ck3 = common_sk_from_simple_seed(4).ref_to(); - proof_of_stake::change_consensus_key( + proof_of_stake::change_consensus_key::<_, governance::Store<_>>( &mut shell.state, &validator1.address, &new2_ck3, @@ -2906,7 +2962,7 @@ mod test_finalize_block { // set, along with consensus key changes // Val2 bonds 1 NAM and changes consensus key - proof_of_stake::bond_tokens( + bond_tokens::<_, governance::Store<_>, token::Store<_>>( &mut shell.state, None, &validator2.address, @@ -2916,7 +2972,7 @@ mod test_finalize_block { ) .unwrap(); let new2_ck2 = common_sk_from_simple_seed(5).ref_to(); - proof_of_stake::change_consensus_key( + proof_of_stake::change_consensus_key::<_, governance::Store<_>>( &mut shell.state, &validator2.address, &new2_ck2, @@ -2925,7 +2981,7 @@ mod test_finalize_block { .unwrap(); // Val3 bonds 1 NAM - proof_of_stake::bond_tokens( + bond_tokens::<_, governance::Store<_>, token::Store<_>>( &mut shell.state, None, &validator3.address, @@ -3792,8 +3848,7 @@ mod test_finalize_block { let (mut shell, _, _, _) = setup(); let validator = shell.mode.get_validator_address().unwrap().to_owned(); - let pos_params = - proof_of_stake::storage::read_pos_params(&shell.state).unwrap(); + let pos_params = read_pos_params(&shell.state).unwrap(); let consensus_key = proof_of_stake::storage::validator_consensus_key_handle(&validator) .get(&shell.state, Epoch::default(), &pos_params) @@ -4212,7 +4267,11 @@ mod test_finalize_block { // Unjail one of the validators let current_epoch = shell.state.in_mem().block.epoch; - unjail_validator(&mut shell.state, &val1.address, current_epoch)?; + unjail_validator::<_, governance::Store<_>>( + &mut shell.state, + &val1.address, + current_epoch, + )?; let pipeline_epoch = current_epoch + params.pipeline_len; // Check that the state is the same until the pipeline epoch, at which @@ -4350,7 +4409,7 @@ mod test_finalize_block { token::Amount::native_whole(200_000), ) .unwrap(); - proof_of_stake::bond_tokens( + bond_tokens::<_, governance::Store<_>, token::Store<_>>( &mut shell.state, Some(&delegator), &val1.address, @@ -4362,7 +4421,7 @@ mod test_finalize_block { // Self-unbond let self_unbond_1_amount = token::Amount::native_whole(84_654); - proof_of_stake::unbond_tokens( + proof_of_stake::unbond_tokens::<_, governance::Store<_>>( &mut shell.state, None, &val1.address, @@ -4405,7 +4464,7 @@ mod test_finalize_block { let (current_epoch, _) = advance_epoch(&mut shell, &pkh1, &votes, None); tracing::debug!("\nUnbonding in epoch 2"); let del_unbond_1_amount = token::Amount::native_whole(18_000); - proof_of_stake::unbond_tokens( + proof_of_stake::unbond_tokens::<_, governance::Store<_>>( &mut shell.state, Some(&delegator), &val1.address, @@ -4451,7 +4510,7 @@ mod test_finalize_block { tracing::debug!("\nBonding in epoch 3"); let self_bond_1_amount = token::Amount::native_whole(9_123); - proof_of_stake::bond_tokens( + bond_tokens::<_, governance::Store<_>, token::Store<_>>( &mut shell.state, None, &val1.address, @@ -4471,7 +4530,7 @@ mod test_finalize_block { assert_eq!(current_epoch.0, 4_u64); let self_unbond_2_amount = token::Amount::native_whole(15_000); - proof_of_stake::unbond_tokens( + proof_of_stake::unbond_tokens::<_, governance::Store<_>>( &mut shell.state, None, &val1.address, @@ -4493,7 +4552,7 @@ mod test_finalize_block { // Delegate let del_2_amount = token::Amount::native_whole(8_144); - proof_of_stake::bond_tokens( + bond_tokens::<_, governance::Store<_>, token::Store<_>>( &mut shell.state, Some(&delegator), &val1.address, @@ -4909,11 +4968,10 @@ mod test_finalize_block { assert_eq!(current_epoch.0, 12_u64); tracing::debug!("\nCHECK BOND AND UNBOND DETAILS"); - let details = proof_of_stake::queries::bonds_and_unbonds( - &shell.state, - None, - None, - ) + let details = proof_of_stake::queries::bonds_and_unbonds::< + _, + governance::Store<_>, + >(&shell.state, None, None) .unwrap(); let del_id = BondId { @@ -5028,7 +5086,11 @@ mod test_finalize_block { // let slash_pool_balance_pre_withdraw = slash_pool_balance; // Withdraw the delegation unbonds, which total to 18_000. This should // only be affected by the slashes in epoch 3 - let del_withdraw = proof_of_stake::withdraw_tokens( + let del_withdraw = proof_of_stake::withdraw_tokens::< + _, + governance::Store<_>, + token::Store<_>, + >( &mut shell.state, Some(&delegator), &val1.address, @@ -5178,7 +5240,7 @@ mod test_finalize_block { // Completely unbond one of the validator to test the pruning at the // pipeline epoch let mut current_epoch = shell.state.in_mem().block.epoch; - proof_of_stake::unbond_tokens( + proof_of_stake::unbond_tokens::<_, governance::Store<_>>( &mut shell.state, None, &val5, @@ -5381,7 +5443,7 @@ mod test_finalize_block { } // Validator 2 unjail itself - proof_of_stake::unjail_validator( + proof_of_stake::unjail_validator::<_, governance::Store<_>>( &mut shell.state, &val2, current_epoch, @@ -6021,4 +6083,16 @@ mod test_finalize_block { assert!(tx_results.are_any_ok()); assert!(tx_results.are_any_err()); } + + /// DI indirection + pub fn read_pos_params( + storage: &S, + ) -> namada_sdk::storage::Result + where + S: StorageRead, + { + proof_of_stake::storage::read_pos_params::>( + storage, + ) + } } diff --git a/crates/node/src/shell/governance.rs b/crates/node/src/shell/governance.rs index b1444f06276..7329b9bc36c 100644 --- a/crates/node/src/shell/governance.rs +++ b/crates/node/src/shell/governance.rs @@ -12,6 +12,7 @@ use namada_sdk::governance::storage::{keys as gov_storage, load_proposals}; use namada_sdk::governance::utils::{ compute_proposal_result, ProposalVotes, TallyResult, TallyType, VotePower, }; +pub use namada_sdk::governance::Store; use namada_sdk::governance::{ storage as gov_api, ProposalVote, ADDRESS as gov_address, }; @@ -26,7 +27,7 @@ use namada_sdk::storage::Epoch; use namada_sdk::token::event::{TokenEvent, TokenOperation}; use namada_sdk::token::read_balance; use namada_sdk::tx::{Code, Data}; -use namada_sdk::{encode, ibc}; +use namada_sdk::{encode, ibc, parameters}; use super::utils::force_read; use super::*; @@ -80,7 +81,7 @@ where H: StorageHasher + Sync + 'static, { let mut proposals_result = ProposalsResult::default(); - let params = read_pos_params(&shell.state)?; + let params = read_pos_params::<_, Store<_>>(&shell.state)?; for id in proposal_ids { let proposal_funds_key = gov_storage::get_funds_key(id); @@ -364,7 +365,8 @@ where source: delegator.clone(), validator: validator.clone(), }; - let delegator_stake = bond_amount(storage, &bond_id, epoch); + let delegator_stake = + bond_amount::<_, Store<_>>(storage, &bond_id, epoch); if let Ok(stake) = delegator_stake { delegators_vote.insert(delegator.clone(), vote_data); @@ -571,7 +573,14 @@ where }, ), PGFTarget::Ibc(target) => ( - ibc::transfer_over_ibc(state, token, &ADDRESS, target), + ibc::transfer_over_ibc::< + _, + parameters::Store<_>, + token::Store<_>, + token::Transfer, + >( + state, token, &ADDRESS, target + ), TokenEvent { descriptor: "pgf-payments-over-ibc".into(), level: EventLevel::Block, diff --git a/crates/node/src/shell/init_chain.rs b/crates/node/src/shell/init_chain.rs index 6a10c9b05c7..498ee5d6bca 100644 --- a/crates/node/src/shell/init_chain.rs +++ b/crates/node/src/shell/init_chain.rs @@ -290,13 +290,13 @@ where ); self.apply_genesis_txs_bonds(&genesis); - proof_of_stake::compute_and_store_total_consensus_stake( - &mut self.state, - current_epoch, - ) + proof_of_stake::compute_and_store_total_consensus_stake::< + _, + governance::Store<_>, + >(&mut self.state, current_epoch) .expect("Could not compute total consensus stake at genesis"); // This has to be done after `apply_genesis_txs_validator_account` - proof_of_stake::copy_genesis_validator_sets( + proof_of_stake::copy_genesis_validator_sets::<_, governance::Store<_>>( &mut self.state, &pos_params, current_epoch, @@ -627,22 +627,25 @@ where .write(&protocol_pk_key(address), &protocol_key.pk.raw) .expect("Unable to set genesis user protocol public key"); - if let Err(err) = proof_of_stake::become_validator( - &mut self.state, - BecomeValidator { - params, - address, - consensus_key: &consensus_key.pk.raw, - protocol_key: &protocol_key.pk.raw, - eth_cold_key: ð_cold_key.pk.raw, - eth_hot_key: ð_hot_key.pk.raw, - current_epoch, - commission_rate: *commission_rate, - max_commission_rate_change: *max_commission_rate_change, - metadata: metadata.clone(), - offset_opt: Some(0), - }, - ) { + if let Err(err) = + proof_of_stake::become_validator::<_, governance::Store<_>>( + &mut self.state, + BecomeValidator { + params, + address, + consensus_key: &consensus_key.pk.raw, + protocol_key: &protocol_key.pk.raw, + eth_cold_key: ð_cold_key.pk.raw, + eth_hot_key: ð_hot_key.pk.raw, + current_epoch, + commission_rate: *commission_rate, + max_commission_rate_change: + *max_commission_rate_change, + metadata: metadata.clone(), + offset_opt: Some(0), + }, + ) + { tracing::warn!( "Genesis init genesis validator tx for {address} \ failed with {err}. Skipping." @@ -675,7 +678,11 @@ where amount, ); - if let Err(err) = proof_of_stake::bond_tokens( + if let Err(err) = proof_of_stake::bond_tokens::< + _, + governance::Store<_>, + token::Store<_>, + >( &mut self.state, Some(&source.address()), validator, diff --git a/crates/node/src/shell/mod.rs b/crates/node/src/shell/mod.rs index 5a19ba73665..cb5c486ceaf 100644 --- a/crates/node/src/shell/mod.rs +++ b/crates/node/src/shell/mod.rs @@ -1066,11 +1066,13 @@ where response, ethereum_tx_data_variants::EthEventsVext::try_from(&tx), ); - if let Err(err) = validate_eth_events_vext( - &self.state, - &ext.0, - self.state.in_mem().get_last_block_height(), - ) { + if let Err(err) = + validate_eth_events_vext::<_, _, governance::Store<_>>( + &self.state, + &ext.0, + self.state.in_mem().get_last_block_height(), + ) + { response.code = ResultCode::InvalidVoteExtension.into(); response.log = format!( "{INVALID_MSG}: Invalid Ethereum events vote \ @@ -1088,11 +1090,13 @@ where &tx ), ); - if let Err(err) = validate_bp_roots_vext( - &self.state, - &ext.0, - self.state.in_mem().get_last_block_height(), - ) { + if let Err(err) = + validate_bp_roots_vext::<_, _, governance::Store<_>>( + &self.state, + &ext.0, + self.state.in_mem().get_last_block_height(), + ) + { response.code = ResultCode::InvalidVoteExtension.into(); response.log = format!( "{INVALID_MSG}: Invalid Bridge pool roots vote \ @@ -1110,19 +1114,21 @@ where &tx ), ); - if let Err(err) = validate_valset_upd_vext( - &self.state, - &ext, - // n.b. only accept validator set updates - // issued at the last committed epoch - // (signing off on the validators of the - // next epoch). at the second height - // within an epoch, the new epoch is - // committed to storage, so `last_epoch` - // reflects the current value of the - // epoch. - self.state.in_mem().last_epoch, - ) { + if let Err(err) = + validate_valset_upd_vext::<_, _, governance::Store<_>>( + &self.state, + &ext, + // n.b. only accept validator set updates + // issued at the last committed epoch + // (signing off on the validators of the + // next epoch). at the second height + // within an epoch, the new epoch is + // committed to storage, so `last_epoch` + // reflects the current value of the + // epoch. + self.state.in_mem().last_epoch, + ) + { response.code = ResultCode::InvalidVoteExtension.into(); response.log = format!( "{INVALID_MSG}: Invalid validator set update vote \ @@ -1288,8 +1294,9 @@ where F: FnMut(common::PublicKey, i64) -> V, { let (current_epoch, _gas) = self.state.in_mem().get_current_epoch(); - let pos_params = proof_of_stake::storage::read_pos_params(&self.state) - .expect("Could not find the PoS parameters"); + let pos_params = + read_pos_params::<_, governance::Store<_>>(&self.state) + .expect("Could not find the PoS parameters"); let validator_set_update_fn = if is_genesis { proof_of_stake::genesis_validator_set_tendermint diff --git a/crates/node/src/shell/prepare_proposal.rs b/crates/node/src/shell/prepare_proposal.rs index b8b80c36080..5f9f3a8776b 100644 --- a/crates/node/src/shell/prepare_proposal.rs +++ b/crates/node/src/shell/prepare_proposal.rs @@ -423,16 +423,18 @@ mod test_prepare_proposal { use namada_sdk::key::RefTo; use namada_sdk::proof_of_stake::storage::{ consensus_validator_set_handle, - read_consensus_validator_set_addresses_with_stake, + read_consensus_validator_set_addresses_with_stake, read_pos_params, }; use namada_sdk::proof_of_stake::types::WeightedValidator; - use namada_sdk::proof_of_stake::{Epoch, PosQueries}; + use namada_sdk::proof_of_stake::Epoch; use namada_sdk::state::collections::lazy_map::{NestedSubKey, SubKey}; - use namada_sdk::storage::{BlockHeight, InnerEthEventsQueue, StorageWrite}; + use namada_sdk::storage::{ + BlockHeight, InnerEthEventsQueue, StorageRead, StorageWrite, + }; use namada_sdk::token::read_denom; use namada_sdk::tx::data::{Fee, TxType}; use namada_sdk::tx::{Authorization, Code, Data, Section, Signed}; - use namada_sdk::{address, token}; + use namada_sdk::{address, governance, token}; use namada_vote_ext::{ethereum_events, ethereum_tx_data_variants}; use super::*; @@ -616,15 +618,16 @@ mod test_prepare_proposal { ..Default::default() }); - let params = shell.state.pos_queries().get_pos_params(); + let params = + read_pos_params::<_, governance::Store<_>>(&shell.state).unwrap(); // artificially change the voting power of the default validator to // one, change the block height, and commit a dummy block, // to move to a new epoch let events_epoch = shell .state - .pos_queries() - .get_epoch(FIRST_HEIGHT) + .get_epoch_at_height(FIRST_HEIGHT) + .unwrap() .expect("Test failed"); let validators_handle = consensus_validator_set_handle().at(&events_epoch); @@ -710,8 +713,8 @@ mod test_prepare_proposal { assert_eq!( shell .state - .pos_queries() - .get_epoch(shell.get_current_decision_height()), + .get_epoch_at_height(shell.get_current_decision_height()) + .unwrap(), Some(Epoch(1)) ); diff --git a/crates/node/src/shell/process_proposal.rs b/crates/node/src/shell/process_proposal.rs index de060e2f119..fecbd20e11f 100644 --- a/crates/node/src/shell/process_proposal.rs +++ b/crates/node/src/shell/process_proposal.rs @@ -4,7 +4,6 @@ use data_encoding::HEXUPPER; use namada_sdk::parameters; use namada_sdk::proof_of_stake::storage::find_validator_by_raw_hash; -use namada_sdk::proof_of_stake::PosQueries; use namada_sdk::tx::data::protocol::ProtocolTxType; use namada_vote_ext::ethereum_tx_data_variants; @@ -31,12 +30,12 @@ where H: 'static + StorageHasher, { fn from(state: &WlState) -> Self { - let max_proposal_bytes = - state.pos_queries().get_max_proposal_bytes().get(); + let max_proposal_bytes = parameters::read_max_proposal_bytes(state) + .expect("Must be able to read ProposalBytes from storage"); let max_block_gas = parameters::get_max_block_gas(state).unwrap(); let user_gas = TxBin::init(max_block_gas); - let txs_bin = TxBin::init(max_proposal_bytes); + let txs_bin = TxBin::init(max_proposal_bytes.get()); Self { user_gas, txs_bin } } } @@ -310,7 +309,11 @@ where ethereum_tx_data_variants::EthEventsVext::try_from(&tx) .map_err(|err| err.to_string()) .and_then(|ext| { - validate_eth_events_vext( + validate_eth_events_vext::< + _, + _, + governance::Store<_>, + >( &self.state, &ext.0, self.state.in_mem().get_last_block_height(), @@ -336,7 +339,11 @@ where ethereum_tx_data_variants::BridgePoolVext::try_from(&tx) .map_err(|err| err.to_string()) .and_then(|ext| { - validate_bp_roots_vext( + validate_bp_roots_vext::< + _, + _, + governance::Store<_>, + >( &self.state, &ext.0, self.state.in_mem().get_last_block_height(), @@ -364,7 +371,7 @@ where ) .map_err(|err| err.to_string()) .and_then(|ext| { - validate_valset_upd_vext( + validate_valset_upd_vext::<_, _, governance::Store<_>>( &self.state, &ext, // n.b. only accept validator set updates @@ -606,8 +613,7 @@ mod test_process_proposal { let voting_powers = shell .state .ethbridge_queries() - .get_consensus_eth_addresses(Some(next_epoch)) - .iter() + .get_consensus_eth_addresses::>(next_epoch) .map(|(eth_addr_book, _, voting_power)| { (eth_addr_book, voting_power) }) diff --git a/crates/node/src/shell/queries.rs b/crates/node/src/shell/queries.rs index bad7126e860..4387548d457 100644 --- a/crates/node/src/shell/queries.rs +++ b/crates/node/src/shell/queries.rs @@ -84,7 +84,6 @@ mod test_queries { use namada_sdk::eth_bridge::SendValsetUpd; use namada_sdk::proof_of_stake::storage::read_consensus_validator_set_addresses_with_stake; use namada_sdk::proof_of_stake::types::WeightedValidator; - use namada_sdk::proof_of_stake::PosQueries; use namada_sdk::storage::Epoch; use namada_sdk::tendermint::abci::types::VoteInfo; @@ -135,8 +134,8 @@ mod test_queries { assert_eq!( shell .state - .pos_queries() - .get_epoch(curr_block_height.into()), + .get_epoch_at_height(curr_block_height.into()) + .unwrap(), Some(Epoch(curr_epoch)) ); assert_eq!( @@ -146,8 +145,7 @@ mod test_queries { .must_send_valset_upd(SendValsetUpd::Now), can_send, ); - let params = - shell.state.pos_queries().get_pos_params(); + let params = read_pos_params::<_, governance::Store<_>>(&shell.state).unwrap(); let consensus_set: Vec = read_consensus_validator_set_addresses_with_stake( &shell.state, diff --git a/crates/node/src/shell/testing/node.rs b/crates/node/src/shell/testing/node.rs index 580a69266d1..54dab68dc3f 100644 --- a/crates/node/src/shell/testing/node.rs +++ b/crates/node/src/shell/testing/node.rs @@ -14,15 +14,13 @@ use namada_sdk::collections::HashMap; use namada_sdk::control_flow::time::Duration; use namada_sdk::eth_bridge::oracle::config::Config as OracleConfig; use namada_sdk::ethereum_events::EthereumEvent; -use namada_sdk::ethereum_structs; use namada_sdk::events::extend::Height as HeightAttr; use namada_sdk::events::log::dumb_queries; use namada_sdk::events::Event; use namada_sdk::hash::Hash; use namada_sdk::key::tm_consensus_key_raw_hash; -use namada_sdk::proof_of_stake::pos_queries::PosQueries; use namada_sdk::proof_of_stake::storage::{ - read_consensus_validator_set_addresses_with_stake, + read_consensus_validator_set_addresses_with_stake, read_pos_params, validator_consensus_key_handle, }; use namada_sdk::proof_of_stake::types::WeightedValidator; @@ -39,6 +37,7 @@ use namada_sdk::tendermint_proto::google::protobuf::Timestamp; use namada_sdk::time::DateTimeUtc; use namada_sdk::tx::data::ResultCode; use namada_sdk::tx::event::Code as CodeAttr; +use namada_sdk::{ethereum_structs, governance}; use regex::Regex; use tokio::sync::mpsc; @@ -402,7 +401,9 @@ impl MockNode { fn prepare_request(&self) -> (Vec, Vec) { let (val1, ck) = { let locked = self.shell.lock().unwrap(); - let params = locked.state.pos_queries().get_pos_params(); + let params = + read_pos_params::<_, governance::Store<_>>(&locked.state) + .unwrap(); let current_epoch = locked.state.in_mem().get_current_epoch().0; let consensus_set: Vec = read_consensus_validator_set_addresses_with_stake( diff --git a/crates/node/src/shell/vote_extensions.rs b/crates/node/src/shell/vote_extensions.rs index 6114ba9b7ab..ed0925f6b8c 100644 --- a/crates/node/src/shell/vote_extensions.rs +++ b/crates/node/src/shell/vote_extensions.rs @@ -109,7 +109,11 @@ where .mode .get_eth_bridge_keypair() .expect("{VALIDATOR_EXPECT_MSG}"); - sign_validator_set_update(&self.state, validator_addr, eth_hot_key) + sign_validator_set_update::<_, _, governance::Store<_>>( + &self.state, + validator_addr, + eth_hot_key, + ) } /// Given a slice of [`TxBytes`], return an iterator over the diff --git a/crates/node/src/shell/vote_extensions/bridge_pool_vext.rs b/crates/node/src/shell/vote_extensions/bridge_pool_vext.rs index 0249e4a6bd9..bedaea167be 100644 --- a/crates/node/src/shell/vote_extensions/bridge_pool_vext.rs +++ b/crates/node/src/shell/vote_extensions/bridge_pool_vext.rs @@ -25,7 +25,7 @@ where >, > + 'iter { vote_extensions.into_iter().map(|vote_extension| { - validate_bp_roots_vext( + validate_bp_roots_vext::<_, _, governance::Store<_>>( &self.state, &vote_extension, self.state.in_mem().get_last_block_height(), @@ -65,19 +65,19 @@ mod test_bp_vote_extensions { use namada_sdk::key::*; use namada_sdk::proof_of_stake::storage::{ consensus_validator_set_handle, - read_consensus_validator_set_addresses_with_stake, + read_consensus_validator_set_addresses_with_stake, read_pos_params, }; use namada_sdk::proof_of_stake::types::{ Position as ValidatorPosition, WeightedValidator, }; use namada_sdk::proof_of_stake::{ - become_validator, BecomeValidator, Epoch, PosQueries, + become_validator, BecomeValidator, Epoch, }; use namada_sdk::state::StorageWrite; use namada_sdk::storage::BlockHeight; use namada_sdk::tendermint::abci::types::VoteInfo; - use namada_sdk::token; use namada_sdk::tx::Signed; + use namada_sdk::{governance, token}; use namada_vote_ext::bridge_pool_roots; use crate::shell::test_utils::*; @@ -95,7 +95,8 @@ mod test_bp_vote_extensions { .expect("Test failed"); // change pipeline length to 1 - let mut params = shell.state.pos_queries().get_pos_params(); + let mut params = + read_pos_params::<_, governance::Store<_>>(&shell.state).unwrap(); params.owned.pipeline_len = 1; let consensus_key = gen_keypair(); @@ -103,7 +104,7 @@ mod test_bp_vote_extensions { let hot_key = gen_secp256k1_keypair(); let cold_key = gen_secp256k1_keypair(); - become_validator( + become_validator::<_, governance::Store<_>>( &mut shell.state, BecomeValidator { params: ¶ms, @@ -169,7 +170,7 @@ mod test_bp_vote_extensions { shell.state.in_mem().get_last_block_height(); shell.commit(); assert!( - validate_bp_roots_vext( + validate_bp_roots_vext::<_, _, governance::Store<_>>( &shell.state, &vote_ext.0, shell.state.in_mem().get_last_block_height() @@ -215,7 +216,7 @@ mod test_bp_vote_extensions { shell.extend_vote_with_bp_roots().expect("Test failed") ); assert!( - validate_bp_roots_vext( + validate_bp_roots_vext::<_, _, governance::Store<_>>( &shell.state, &vote_ext.0, shell.state.in_mem().get_last_block_height(), @@ -294,7 +295,7 @@ mod test_bp_vote_extensions { } .sign(shell.mode.get_protocol_key().expect("Test failed")); assert!( - validate_bp_roots_vext( + validate_bp_roots_vext::<_, _, governance::Store<_>>( &shell.state, &bp_root.0, shell.get_current_decision_height(), @@ -333,7 +334,7 @@ mod test_bp_vote_extensions { } .sign(&bertha_keypair()); assert!( - validate_bp_roots_vext( + validate_bp_roots_vext::<_, _, governance::Store<_>>( &shell.state, &bp_root.0, shell.state.in_mem().get_last_block_height() @@ -358,7 +359,7 @@ mod test_bp_vote_extensions { .sign(shell.mode.get_protocol_key().expect("Test failed")); assert!( - validate_bp_roots_vext( + validate_bp_roots_vext::<_, _, governance::Store<_>>( &shell.state, &bp_root.0, shell.state.in_mem().get_last_block_height() @@ -420,7 +421,7 @@ mod test_bp_vote_extensions { } .sign(shell.mode.get_protocol_key().expect("Test failed")); assert!( - validate_bp_roots_vext( + validate_bp_roots_vext::<_, _, governance::Store<_>>( &shell.state, &bp_root.0, shell.state.in_mem().get_last_block_height() @@ -453,7 +454,7 @@ mod test_bp_vote_extensions { } .sign(shell.mode.get_protocol_key().expect("Test failed")); assert!( - validate_bp_roots_vext( + validate_bp_roots_vext::<_, _, governance::Store<_>>( &shell.state, &bp_root.0, shell.state.in_mem().get_last_block_height() @@ -513,7 +514,7 @@ mod test_bp_vote_extensions { } .sign(shell.mode.get_protocol_key().expect("Test failed")); assert!( - validate_bp_roots_vext( + validate_bp_roots_vext::<_, _, governance::Store<_>>( &shell.state, &bp_root.0, shell.get_current_decision_height() @@ -533,7 +534,7 @@ mod test_bp_vote_extensions { } .sign(shell.mode.get_protocol_key().expect("Test failed")); assert!( - validate_bp_roots_vext( + validate_bp_roots_vext::<_, _, governance::Store<_>>( &shell.state, &bp_root.0, shell.get_current_decision_height() @@ -593,7 +594,7 @@ mod test_bp_vote_extensions { } .sign(shell.mode.get_protocol_key().expect("Test failed")); assert!( - validate_bp_roots_vext( + validate_bp_roots_vext::<_, _, governance::Store<_>>( &shell.state, &bp_root.0, shell.get_current_decision_height() diff --git a/crates/node/src/shell/vote_extensions/eth_events.rs b/crates/node/src/shell/vote_extensions/eth_events.rs index 236ebd36990..9dfbe59b48a 100644 --- a/crates/node/src/shell/vote_extensions/eth_events.rs +++ b/crates/node/src/shell/vote_extensions/eth_events.rs @@ -49,7 +49,7 @@ where >, > + 'iter { vote_extensions.into_iter().map(|vote_extension| { - validate_eth_events_vext( + validate_eth_events_vext::<_, _, governance::Store<_>>( &self.state, &vote_extension, self.state.in_mem().get_last_block_height(), @@ -140,18 +140,20 @@ mod test_vote_extensions { use namada_sdk::address::testing::gen_established_address; use namada_sdk::eth_bridge::storage::bridge_pool; use namada_sdk::eth_bridge::storage::eth_bridge_queries::is_bridge_comptime_enabled; + use namada_sdk::eth_bridge::test_utils::GovStore; use namada_sdk::eth_bridge::EthBridgeQueries; use namada_sdk::ethereum_events::{ EthAddress, EthereumEvent, TransferToEthereum, Uint, }; + use namada_sdk::governance; use namada_sdk::hash::Hash; use namada_sdk::key::*; + use namada_sdk::proof_of_stake::queries::get_consensus_validator_from_protocol_pk; use namada_sdk::proof_of_stake::storage::{ consensus_validator_set_handle, - read_consensus_validator_set_addresses_with_stake, + read_consensus_validator_set_addresses_with_stake, read_pos_params, }; use namada_sdk::proof_of_stake::types::WeightedValidator; - use namada_sdk::proof_of_stake::PosQueries; use namada_sdk::state::collections::lazy_map::{NestedSubKey, SubKey}; use namada_sdk::storage::{Epoch, InnerEthEventsQueue, StorageWrite}; use namada_sdk::tendermint::abci::types::VoteInfo; @@ -375,7 +377,7 @@ mod test_vote_extensions { } .sign(&signing_key); assert!( - validate_eth_events_vext( + validate_eth_events_vext::<_, _, governance::Store<_>>( &shell.state, ðereum_events, shell.get_current_decision_height(), @@ -453,7 +455,8 @@ mod test_vote_extensions { .into_iter() .collect(); - let params = shell.state.pos_queries().get_pos_params(); + let params = + read_pos_params::<_, governance::Store<_>>(&shell.state).unwrap(); let val1 = consensus_set[0].clone(); let pkh1 = get_pkh_from_address( &shell.state, @@ -479,29 +482,33 @@ mod test_vote_extensions { }; assert_eq!(shell.start_new_epoch(Some(req)).0, 1); assert!( - shell - .state - .pos_queries() - .get_validator_from_protocol_pk(&signing_key.ref_to(), None) - .is_err() + get_consensus_validator_from_protocol_pk::<_, GovStore<_>>( + &shell.state, + &signing_key.ref_to(), + None + ) + .unwrap() + .is_none() ); let prev_epoch = Epoch(shell.state.in_mem().get_current_epoch().0.0 - 1); assert!( - shell - .shell - .state - .pos_queries() - .get_validator_from_protocol_pk( - &signing_key.ref_to(), - Some(prev_epoch) - ) - .is_ok() + get_consensus_validator_from_protocol_pk::<_, GovStore<_>>( + &shell.state, + &signing_key.ref_to(), + Some(prev_epoch) + ) + .unwrap() + .is_some() ); assert!( - validate_eth_events_vext(&shell.state, &vote_ext, signed_height) - .is_ok() + validate_eth_events_vext::<_, _, governance::Store<_>>( + &shell.state, + &vote_ext, + signed_height + ) + .is_ok() ); } @@ -539,7 +546,7 @@ mod test_vote_extensions { let signed_vext = ethereum_events .sign(shell.mode.get_protocol_key().expect("Test failed")); assert!( - validate_eth_events_vext( + validate_eth_events_vext::<_, _, governance::Store<_>>( &shell.state, &signed_vext, shell.state.in_mem().get_last_block_height() @@ -577,7 +584,7 @@ mod test_vote_extensions { .sign(shell.mode.get_protocol_key().expect("Test failed")); assert!( - validate_eth_events_vext( + validate_eth_events_vext::<_, _, governance::Store<_>>( &shell.state, &vote_ext, shell.state.in_mem().get_last_block_height() diff --git a/crates/node/src/shell/vote_extensions/val_set_update.rs b/crates/node/src/shell/vote_extensions/val_set_update.rs index 9ac1e3322bb..16e519c628f 100644 --- a/crates/node/src/shell/vote_extensions/val_set_update.rs +++ b/crates/node/src/shell/vote_extensions/val_set_update.rs @@ -26,7 +26,7 @@ where >, > + '_ { vote_extensions.into_iter().map(|vote_extension| { - validate_valset_upd_vext( + validate_valset_upd_vext::<_, _, governance::Store<_>>( &self.state, &vote_extension, self.state.in_mem().get_current_epoch().0, @@ -112,14 +112,17 @@ where mod test_vote_extensions { use namada_apps_lib::wallet; use namada_sdk::eth_bridge::storage::eth_bridge_queries::is_bridge_comptime_enabled; + use namada_sdk::eth_bridge::test_utils::GovStore; use namada_sdk::eth_bridge::EthBridgeQueries; + use namada_sdk::governance; use namada_sdk::key::RefTo; + use namada_sdk::proof_of_stake::queries::get_consensus_validator_from_protocol_pk; use namada_sdk::proof_of_stake::storage::{ consensus_validator_set_handle, - read_consensus_validator_set_addresses_with_stake, + read_consensus_validator_set_addresses_with_stake, read_pos_params, }; use namada_sdk::proof_of_stake::types::WeightedValidator; - use namada_sdk::proof_of_stake::{Epoch, PosQueries}; + use namada_sdk::proof_of_stake::Epoch; use namada_sdk::state::collections::lazy_map::{NestedSubKey, SubKey}; use namada_sdk::tendermint::abci::types::VoteInfo; use namada_vote_ext::validator_set_update; @@ -151,8 +154,7 @@ mod test_vote_extensions { shell .state .ethbridge_queries() - .get_consensus_eth_addresses(Some(next_epoch)) - .iter() + .get_consensus_eth_addresses::>(next_epoch) .map(|(eth_addr_book, _, voting_power)| { (eth_addr_book, voting_power) }) @@ -167,7 +169,7 @@ mod test_vote_extensions { } .sign(eth_bridge_key); assert!( - validate_valset_upd_vext( + validate_valset_upd_vext::<_, _, governance::Store<_>>( &shell.state, &validator_set_update, signing_epoch, @@ -197,8 +199,7 @@ mod test_vote_extensions { shell .state .ethbridge_queries() - .get_consensus_eth_addresses(Some(next_epoch)) - .iter() + .get_consensus_eth_addresses::>(next_epoch) .map(|(eth_addr_book, _, voting_power)| { (eth_addr_book, voting_power) }) @@ -212,7 +213,7 @@ mod test_vote_extensions { } .sign(ð_bridge_key); assert!( - validate_valset_upd_vext( + validate_valset_upd_vext::<_, _, governance::Store<_>>( &shell.state, &validator_set_update, signing_epoch, @@ -280,8 +281,7 @@ mod test_vote_extensions { shell .state .ethbridge_queries() - .get_consensus_eth_addresses(Some(next_epoch)) - .iter() + .get_consensus_eth_addresses::>(next_epoch) .map(|(eth_addr_book, _, voting_power)| { (eth_addr_book, voting_power) }) @@ -296,7 +296,8 @@ mod test_vote_extensions { assert!(vote_ext.data.voting_powers.is_empty()); // we advance forward to the next epoch - let params = shell.state.pos_queries().get_pos_params(); + let params = + read_pos_params::<_, governance::Store<_>>(&shell.state).unwrap(); let mut consensus_set: Vec = read_consensus_validator_set_addresses_with_stake( &shell.state, @@ -331,29 +332,33 @@ mod test_vote_extensions { }; assert_eq!(shell.start_new_epoch(Some(req)).0, 1); assert!( - shell - .state - .pos_queries() - .get_validator_from_protocol_pk(&protocol_key.ref_to(), None) - .is_err() + get_consensus_validator_from_protocol_pk::<_, GovStore<_>>( + &shell.state, + &protocol_key.ref_to(), + None + ) + .unwrap() + .is_none() ); let prev_epoch = shell.state.in_mem().get_current_epoch().0 - 1; assert!( - shell - .shell - .state - .pos_queries() - .get_validator_from_protocol_pk( - &protocol_key.ref_to(), - Some(prev_epoch) - ) - .is_ok() + get_consensus_validator_from_protocol_pk::<_, GovStore<_>>( + &shell.state, + &protocol_key.ref_to(), + Some(prev_epoch) + ) + .unwrap() + .is_some() ); // check validation of the vext passes assert!( - validate_valset_upd_vext(&shell.state, &vote_ext, signing_epoch) - .is_ok() + validate_valset_upd_vext::<_, _, governance::Store<_>>( + &shell.state, + &vote_ext, + signing_epoch + ) + .is_ok() ); } @@ -381,8 +386,9 @@ mod test_vote_extensions { shell .state .ethbridge_queries() - .get_consensus_eth_addresses(Some(next_epoch)) - .iter() + .get_consensus_eth_addresses::>( + next_epoch, + ) .map(|(eth_addr_book, _, voting_power)| { (eth_addr_book, voting_power) }) @@ -398,7 +404,7 @@ mod test_vote_extensions { Some(ext) }; assert!( - validate_valset_upd_vext( + validate_valset_upd_vext::<_, _, governance::Store<_>>( &shell.state, &validator_set_update.unwrap(), signing_epoch, diff --git a/crates/parameters/src/lib.rs b/crates/parameters/src/lib.rs index abdd73b8086..55a91c75d59 100644 --- a/crates/parameters/src/lib.rs +++ b/crates/parameters/src/lib.rs @@ -68,6 +68,18 @@ where fn epochs_per_year(storage: &S) -> Result { read_epochs_per_year(storage) } + + fn estimate_max_block_time_from_blocks_and_params( + storage: &S, + last_block_height: BlockHeight, + num_blocks_to_read: u64, + ) -> Result { + estimate_max_block_time_from_blocks_and_params( + storage, + last_block_height, + num_blocks_to_read, + ) + } } impl Write for Store @@ -342,6 +354,20 @@ where .into_storage_result() } +/// Retrieve the `max_proposal_bytes` consensus parameter from storage. +pub fn read_max_proposal_bytes( + storage: &S, +) -> namada_storage::Result +where + S: StorageRead, +{ + let key = storage::get_max_proposal_bytes_key(); + let result = storage.read(&key)?; + result + .ok_or(ReadError::ParametersMissing) + .into_storage_result() +} + /// Read all the parameters from storage. Returns the parameters and gas /// cost. pub fn read(storage: &S) -> namada_storage::Result diff --git a/crates/parameters/src/vp.rs b/crates/parameters/src/vp.rs index 26b7c5c8e57..b738bb61aa5 100644 --- a/crates/parameters/src/vp.rs +++ b/crates/parameters/src/vp.rs @@ -30,7 +30,6 @@ pub type Result = std::result::Result; pub struct ParametersVp<'ctx, S, CA, EVAL, Gov> where S: 'static + StateRead, - EVAL: VpEvaluator<'ctx, S, CA, EVAL>, { /// Context to interact with the host structures. pub ctx: Ctx<'ctx, S, CA, EVAL>, diff --git a/crates/proof_of_stake/Cargo.toml b/crates/proof_of_stake/Cargo.toml index f858812ee9a..c53a567b330 100644 --- a/crates/proof_of_stake/Cargo.toml +++ b/crates/proof_of_stake/Cargo.toml @@ -26,14 +26,11 @@ namada_account = { path = "../account" } namada_controller = { path = "../controller" } namada_core = { path = "../core" } namada_events = { path = "../events", default-features = false } -namada_governance = { path = "../governance" } namada_macros = { path = "../macros" } namada_migrations = { path = "../migrations", optional = true } namada_state = { path = "../state" } namada_storage = { path = "../storage" } namada_systems = { path = "../systems" } -namada_parameters = { path = "../parameters" } -namada_trans_token = { path = "../trans_token" } namada_tx = { path = "../tx" } namada_vp = { path = "../vp" } @@ -52,7 +49,10 @@ tracing.workspace = true [dev-dependencies] namada_core = { path = "../core", features = ["testing"] } namada_events = { path = "../events", features = ["testing"] } +namada_governance = { path = "../governance" } +namada_parameters = { path = "../parameters" } namada_state = { path = "../state", features = ["testing"] } +namada_trans_token = { path = "../trans_token" } assert_matches.workspace = true itertools.workspace = true diff --git a/crates/proof_of_stake/src/epoched.rs b/crates/proof_of_stake/src/epoched.rs index f3f3ca2c8a0..dd37c92b1da 100644 --- a/crates/proof_of_stake/src/epoched.rs +++ b/crates/proof_of_stake/src/epoched.rs @@ -15,6 +15,7 @@ use namada_migrations::*; use namada_storage::collections::lazy_map::{LazyMap, NestedMap}; use namada_storage::collections::{self, LazyCollection}; use namada_storage::{StorageRead, StorageWrite}; +use namada_systems::governance; use crate::parameters::PosParams; use crate::read_pos_params; @@ -133,7 +134,7 @@ where } /// Initialize or set the value at the given epoch offset. - pub fn set( + pub fn set( &self, storage: &mut S, value: Data, @@ -142,8 +143,9 @@ where ) -> namada_storage::Result<()> where S: StorageWrite + StorageRead, + Gov: governance::Read, { - let params = read_pos_params(storage)?; + let params = read_pos_params::(storage)?; self.update_data(storage, ¶ms, current_epoch)?; self.set_at_epoch(storage, value, current_epoch, offset) } @@ -551,7 +553,7 @@ where /// Initialize or add a value to the current delta value at the given epoch /// offset. - pub fn add( + pub fn add( &self, storage: &mut S, value: Data, @@ -560,9 +562,10 @@ where ) -> namada_storage::Result<()> where S: StorageWrite + StorageRead, + Gov: governance::Read, Data: Default, { - let params = read_pos_params(storage)?; + let params = read_pos_params::(storage)?; self.update_data(storage, ¶ms, current_epoch)?; let cur_value = self .get_delta_val(storage, current_epoch.unchecked_add(offset))? @@ -572,7 +575,7 @@ where } /// Initialize or set the value at the given epoch offset. - pub fn set( + pub fn set( &self, storage: &mut S, value: Data, @@ -581,8 +584,9 @@ where ) -> namada_storage::Result<()> where S: StorageWrite + StorageRead, + Gov: governance::Read, { - let params = read_pos_params(storage)?; + let params = read_pos_params::(storage)?; self.update_data(storage, ¶ms, current_epoch)?; self.set_at_epoch(storage, value, current_epoch, offset) } @@ -1120,6 +1124,7 @@ mod test { use test_log::test; use super::*; + use crate::tests::GovStore; use crate::types::GenesisValidator; #[test] @@ -1140,19 +1145,19 @@ mod test { assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(0)); - epoched.set(&mut s, 1, Epoch(0), 0)?; + epoched.set::<_, GovStore<_>>(&mut s, 1, Epoch(0), 0)?; assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(0))); assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); - epoched.set(&mut s, 2, Epoch(1), 0)?; + epoched.set::<_, GovStore<_>>(&mut s, 2, Epoch(1), 0)?; assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(1))); assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); assert_eq!(data_handler.get(&s, &Epoch(1))?, Some(2)); // Nothing is trimmed yet, oldest kept epoch is 0 - epoched.set(&mut s, 3, Epoch(2), 0)?; + epoched.set::<_, GovStore<_>>(&mut s, 3, Epoch(2), 0)?; assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(2))); assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); @@ -1160,7 +1165,7 @@ mod test { assert_eq!(data_handler.get(&s, &Epoch(2))?, Some(3)); // Epoch 0 should be trimmed now, oldest kept epoch is 1 - epoched.set(&mut s, 4, Epoch(3), 0)?; + epoched.set::<_, GovStore<_>>(&mut s, 4, Epoch(3), 0)?; assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(3))); assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(1))); assert_eq!(data_handler.get(&s, &Epoch(0))?, None); @@ -1169,7 +1174,7 @@ mod test { assert_eq!(data_handler.get(&s, &Epoch(3))?, Some(4)); // Anything before epoch 3 should be trimmed - epoched.set(&mut s, 5, Epoch(5), 0)?; + epoched.set::<_, GovStore<_>>(&mut s, 5, Epoch(5), 0)?; assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(5))); assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(3))); assert_eq!(data_handler.get(&s, &Epoch(0))?, None); @@ -1179,7 +1184,7 @@ mod test { assert_eq!(data_handler.get(&s, &Epoch(5))?, Some(5)); // Anything before epoch 8 should be trimmed - epoched.set(&mut s, 6, Epoch(10), 0)?; + epoched.set::<_, GovStore<_>>(&mut s, 6, Epoch(10), 0)?; assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(10))); assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(8))); for epoch in Epoch(0).iter_range(7) { @@ -1209,25 +1214,25 @@ mod test { assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(0)); - epoched.set(&mut s, 1, Epoch(0), 0)?; + epoched.set::<_, GovStore<_>>(&mut s, 1, Epoch(0), 0)?; assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(0))); assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); - epoched.set(&mut s, 2, Epoch(1), 0)?; + epoched.set::<_, GovStore<_>>(&mut s, 2, Epoch(1), 0)?; assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(1))); assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); assert_eq!(data_handler.get(&s, &Epoch(1))?, Some(2)); - epoched.set(&mut s, 3, Epoch(2), 0)?; + epoched.set::<_, GovStore<_>>(&mut s, 3, Epoch(2), 0)?; assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(2))); assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); assert_eq!(data_handler.get(&s, &Epoch(1))?, Some(2)); assert_eq!(data_handler.get(&s, &Epoch(2))?, Some(3)); - epoched.set(&mut s, 4, Epoch(3), 0)?; + epoched.set::<_, GovStore<_>>(&mut s, 4, Epoch(3), 0)?; assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(3))); assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); @@ -1235,7 +1240,7 @@ mod test { assert_eq!(data_handler.get(&s, &Epoch(2))?, Some(3)); assert_eq!(data_handler.get(&s, &Epoch(3))?, Some(4)); - epoched.set(&mut s, 5, Epoch(5), 0)?; + epoched.set::<_, GovStore<_>>(&mut s, 5, Epoch(5), 0)?; assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(5))); assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); @@ -1244,7 +1249,7 @@ mod test { assert_eq!(data_handler.get(&s, &Epoch(3))?, Some(4)); assert_eq!(data_handler.get(&s, &Epoch(5))?, Some(5)); - epoched.set(&mut s, 6, Epoch(10), 0)?; + epoched.set::<_, GovStore<_>>(&mut s, 6, Epoch(10), 0)?; assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(10))); assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); @@ -1279,19 +1284,19 @@ mod test { assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(0)); - epoched.set(&mut s, 1, Epoch(0), 0)?; + epoched.set::<_, GovStore<_>>(&mut s, 1, Epoch(0), 0)?; assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(0))); assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); - epoched.set(&mut s, 2, Epoch(1), 0)?; + epoched.set::<_, GovStore<_>>(&mut s, 2, Epoch(1), 0)?; assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(1))); assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); assert_eq!(data_handler.get(&s, &Epoch(1))?, Some(2)); // Nothing is trimmed yet, oldest kept epoch is 0 - epoched.set(&mut s, 3, Epoch(2), 0)?; + epoched.set::<_, GovStore<_>>(&mut s, 3, Epoch(2), 0)?; assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(2))); assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); @@ -1299,7 +1304,7 @@ mod test { assert_eq!(data_handler.get(&s, &Epoch(2))?, Some(3)); // Epoch 0 should be trimmed now, oldest kept epoch is 1 - epoched.set(&mut s, 4, Epoch(3), 0)?; + epoched.set::<_, GovStore<_>>(&mut s, 4, Epoch(3), 0)?; assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(3))); assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(1))); assert_eq!(data_handler.get(&s, &Epoch(0))?, None); @@ -1309,7 +1314,7 @@ mod test { assert_eq!(data_handler.get(&s, &Epoch(3))?, Some(4)); // Anything before epoch 3 should be trimmed - epoched.set(&mut s, 5, Epoch(5), 0)?; + epoched.set::<_, GovStore<_>>(&mut s, 5, Epoch(5), 0)?; assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(5))); assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(3))); assert_eq!(data_handler.get(&s, &Epoch(0))?, None); @@ -1320,7 +1325,7 @@ mod test { assert_eq!(data_handler.get(&s, &Epoch(5))?, Some(5)); // Anything before epoch 8 should be trimmed - epoched.set(&mut s, 6, Epoch(10), 0)?; + epoched.set::<_, GovStore<_>>(&mut s, 6, Epoch(10), 0)?; assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(10))); assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(8))); for epoch in Epoch(0).iter_range(7) { @@ -1354,25 +1359,25 @@ mod test { assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(0)); - epoched.set(&mut s, 1, Epoch(0), 0)?; + epoched.set::<_, GovStore<_>>(&mut s, 1, Epoch(0), 0)?; assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(0))); assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); - epoched.set(&mut s, 2, Epoch(1), 0)?; + epoched.set::<_, GovStore<_>>(&mut s, 2, Epoch(1), 0)?; assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(1))); assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); assert_eq!(data_handler.get(&s, &Epoch(1))?, Some(2)); - epoched.set(&mut s, 3, Epoch(2), 0)?; + epoched.set::<_, GovStore<_>>(&mut s, 3, Epoch(2), 0)?; assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(2))); assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); assert_eq!(data_handler.get(&s, &Epoch(1))?, Some(2)); assert_eq!(data_handler.get(&s, &Epoch(2))?, Some(3)); - epoched.set(&mut s, 4, Epoch(3), 0)?; + epoched.set::<_, GovStore<_>>(&mut s, 4, Epoch(3), 0)?; assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(3))); assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); @@ -1380,7 +1385,7 @@ mod test { assert_eq!(data_handler.get(&s, &Epoch(2))?, Some(3)); assert_eq!(data_handler.get(&s, &Epoch(3))?, Some(4)); - epoched.set(&mut s, 5, Epoch(5), 0)?; + epoched.set::<_, GovStore<_>>(&mut s, 5, Epoch(5), 0)?; assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(5))); assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); @@ -1389,7 +1394,7 @@ mod test { assert_eq!(data_handler.get(&s, &Epoch(3))?, Some(4)); assert_eq!(data_handler.get(&s, &Epoch(5))?, Some(5)); - epoched.set(&mut s, 6, Epoch(10), 0)?; + epoched.set::<_, GovStore<_>>(&mut s, 6, Epoch(10), 0)?; assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(10))); assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); @@ -1403,7 +1408,7 @@ mod test { assert_eq!(data_handler.get(&s, &Epoch(9))?, None); assert_eq!(data_handler.get(&s, &Epoch(10))?, Some(6)); - epoched.add(&mut s, 15, Epoch(10), 0)?; + epoched.add::<_, GovStore<_>>(&mut s, 15, Epoch(10), 0)?; assert_eq!(epoched.get_last_update(&s)?, Some(Epoch(10))); assert_eq!(epoched.get_oldest_epoch(&s)?, Some(Epoch(0))); assert_eq!(data_handler.get(&s, &Epoch(0))?, Some(1)); @@ -1425,7 +1430,7 @@ mod test { let gov_params = namada_governance::parameters::GovernanceParameters::default(); gov_params.init_storage(&mut s)?; - crate::test_utils::init_genesis_helper( + crate::tests::init_genesis_helper( &mut s, &PosParams::default(), [GenesisValidator { diff --git a/crates/proof_of_stake/src/lib.rs b/crates/proof_of_stake/src/lib.rs index 733677583d8..ca7204fb941 100644 --- a/crates/proof_of_stake/src/lib.rs +++ b/crates/proof_of_stake/src/lib.rs @@ -20,7 +20,6 @@ pub mod epoched; pub mod event; pub mod parameters; -pub mod pos_queries; pub mod queries; pub mod rewards; pub mod slashing; @@ -49,13 +48,13 @@ use namada_core::key::common; use namada_core::storage::BlockHeight; pub use namada_core::storage::{Epoch, Key, KeySeg}; use namada_core::tendermint::abci::types::Misbehavior; +use namada_core::token; use namada_events::EmitEvents; use namada_storage::collections::lazy_map::{self, Collectable, LazyMap}; use namada_storage::{OptionExt, StorageRead, StorageWrite}; pub use namada_systems::proof_of_stake::*; -pub use namada_trans_token as token; +use namada_systems::{governance, trans_token}; pub use parameters::{OwnedPosParams, PosParams}; -pub use pos_queries::PosQueries; use storage::write_validator_name; pub use types::GenesisValidator; use types::{into_tm_voting_power, DelegationEpochs}; @@ -97,10 +96,9 @@ use crate::storage::{ }; use crate::storage_key::{bonds_for_source_prefix, is_bond_key}; use crate::types::{ - BondId, ConsensusValidator, ConsensusValidatorSet, - EagerRedelegatedBondsMap, RedelegatedBondsOrUnbonds, RedelegatedTokens, - ResultSlashing, Slash, Unbonds, ValidatorMetaData, ValidatorSetUpdate, - ValidatorState, VoteInfo, + BondId, ConsensusValidator, EagerRedelegatedBondsMap, + RedelegatedBondsOrUnbonds, RedelegatedTokens, ResultSlashing, Slash, + Unbonds, ValidatorMetaData, ValidatorSetUpdate, ValidatorState, VoteInfo, }; use crate::validator_set_update::{ copy_validator_sets_and_positions, insert_validator_into_validator_set, @@ -176,15 +174,16 @@ where /// Copies the validator sets into all epochs up through the pipeline epoch at /// genesis. -pub fn copy_genesis_validator_sets( +pub fn copy_genesis_validator_sets( storage: &mut S, params: &OwnedPosParams, current_epoch: Epoch, ) -> Result<()> where S: StorageRead + StorageWrite, + Gov: governance::Read, { - let params = read_non_pos_owned_params(storage, params.clone())?; + let params = read_non_pos_owned_params::<_, Gov>(storage, params.clone())?; // Copy the genesis validator sets up to the pipeline epoch for epoch in (current_epoch.next()).iter_range(params.pipeline_len) { @@ -254,7 +253,7 @@ where /// Self-bond tokens to a validator when `source` is `None` or equal to /// the `validator` address, or delegate tokens from the `source` to the /// `validator`. -pub fn bond_tokens( +pub fn bond_tokens( storage: &mut S, source: Option<&Address>, validator: &Address, @@ -264,6 +263,8 @@ pub fn bond_tokens( ) -> Result<()> where S: StorageRead + StorageWrite, + Gov: governance::Read, + Token: trans_token::Write, { tracing::debug!( "Bonding token amount {} at epoch {current_epoch}", @@ -286,9 +287,9 @@ where tracing::debug!("Source {source} --> Validator {validator}"); let staking_token = staking_token_address(storage); - token::transfer(storage, &staking_token, source, &ADDRESS, amount)?; + Token::transfer(storage, &staking_token, source, &ADDRESS, amount)?; - let params = read_pos_params(storage)?; + let params = read_pos_params::(storage)?; let offset = offset_opt.unwrap_or(params.pipeline_len); let offset_epoch = checked!(current_epoch + offset)?; @@ -307,8 +308,13 @@ where // Initialize or update the bond at the pipeline offset let bond_handle = bond_handle(source, validator); let total_bonded_handle = total_bonded_handle(validator); - bond_handle.add(storage, amount, current_epoch, offset)?; - total_bonded_handle.add(storage, amount, current_epoch, offset)?; + bond_handle.add::(storage, amount, current_epoch, offset)?; + total_bonded_handle.add::( + storage, + amount, + current_epoch, + offset, + )?; if tracing::level_enabled!(tracing::Level::DEBUG) { let bonds = find_bonds(storage, source, validator)?; @@ -332,7 +338,7 @@ where Some(ValidatorState::Jailed) | Some(ValidatorState::Inactive) ); if !is_jailed_or_inactive_at_offset { - update_validator_set( + update_validator_set::( storage, ¶ms, validator, @@ -343,7 +349,7 @@ where } // Update the validator and total deltas - update_validator_deltas( + update_validator_deltas::( storage, ¶ms, validator, @@ -352,7 +358,7 @@ where offset_opt, )?; - update_total_deltas( + update_total_deltas::( storage, ¶ms, amount.change(), @@ -390,12 +396,13 @@ where } /// Compute and then store the total consensus stake -pub fn compute_and_store_total_consensus_stake( +pub fn compute_and_store_total_consensus_stake( storage: &mut S, epoch: Epoch, ) -> Result<()> where S: StorageRead + StorageWrite, + Gov: governance::Read, { let total = compute_total_consensus_stake(storage, epoch)?; tracing::debug!( @@ -403,7 +410,7 @@ where epoch, total.to_string_native() ); - total_consensus_stake_handle().set(storage, total, epoch, 0) + total_consensus_stake_handle().set::(storage, total, epoch, 0) } /// Unbond tokens that are bonded between a validator and a source (self or @@ -411,7 +418,7 @@ where /// /// This fn is also called during redelegation for a source validator, in /// which case the `is_redelegation` param must be true. -pub fn unbond_tokens( +pub fn unbond_tokens( storage: &mut S, source: Option<&Address>, validator: &Address, @@ -421,12 +428,13 @@ pub fn unbond_tokens( ) -> Result where S: StorageRead + StorageWrite, + Gov: governance::Read, { if amount.is_zero() { return Ok(ResultSlashing::default()); } - let params = read_pos_params(storage)?; + let params = read_pos_params::(storage)?; let pipeline_epoch = checked!(current_epoch + params.pipeline_len)?; let withdrawable_epoch = checked!(current_epoch + params.withdrawable_epoch_offset())?; @@ -557,7 +565,7 @@ where } // Replace bond amount for partial unbond, if any. if let Some((bond_epoch, new_bond_amount)) = bonds_to_unbond.new_entry { - bonds_handle.set(storage, new_bond_amount, bond_epoch, 0)?; + bonds_handle.set::(storage, new_bond_amount, bond_epoch, 0)?; } // If the bond is now completely empty, remove the validator from the @@ -738,7 +746,7 @@ where Some(ValidatorState::Jailed) | Some(ValidatorState::Inactive) ); if !is_jailed_or_inactive_at_pipeline { - update_validator_set( + update_validator_set::( storage, ¶ms, validator, @@ -749,7 +757,7 @@ where } // Update the validator and total deltas at the pipeline offset - update_validator_deltas( + update_validator_deltas::( storage, ¶ms, validator, @@ -757,7 +765,7 @@ where current_epoch, None, )?; - update_total_deltas( + update_total_deltas::( storage, ¶ms, change_after_slashing, @@ -1286,12 +1294,13 @@ pub struct BecomeValidator<'a> { } /// Initialize data for a new validator. -pub fn become_validator( +pub fn become_validator( storage: &mut S, args: BecomeValidator<'_>, ) -> Result<()> where S: StorageRead + StorageWrite, + Gov: governance::Read, { let BecomeValidator { params, @@ -1323,7 +1332,7 @@ where // The address may not have any bonds if it is going to be initialized as a // validator - if has_bonds(storage, address)? { + if has_bonds::(storage, address)? { return Err(namada_storage::Error::new_const( "The given address has delegations and therefore cannot become a \ validator. Unbond first.", @@ -1348,37 +1357,37 @@ where write_validator_metadata(storage, address, &metadata)?; // Epoched validator data - validator_consensus_key_handle(address).set( + validator_consensus_key_handle(address).set::( storage, consensus_key.clone(), current_epoch, offset, )?; - validator_protocol_key_handle(address).set( + validator_protocol_key_handle(address).set::( storage, protocol_key.clone(), current_epoch, offset, )?; - validator_eth_hot_key_handle(address).set( + validator_eth_hot_key_handle(address).set::( storage, eth_hot_key.clone(), current_epoch, offset, )?; - validator_eth_cold_key_handle(address).set( + validator_eth_cold_key_handle(address).set::( storage, eth_cold_key.clone(), current_epoch, offset, )?; - validator_commission_rate_handle(address).set( + validator_commission_rate_handle(address).set::( storage, commission_rate, current_epoch, offset, )?; - validator_deltas_handle(address).set( + validator_deltas_handle(address).set::( storage, token::Change::zero(), current_epoch, @@ -1387,14 +1396,14 @@ where // The validator's stake at initialization is 0, so its state is immediately // below-threshold - validator_state_handle(address).set( + validator_state_handle(address).set::( storage, ValidatorState::BelowThreshold, current_epoch, offset, )?; - insert_validator_into_validator_set( + insert_validator_into_validator_set::( storage, params, address, @@ -1407,7 +1416,7 @@ where } /// Consensus key change for a validator -pub fn change_consensus_key( +pub fn change_consensus_key( storage: &mut S, validator: &Address, consensus_key: &common::PublicKey, @@ -1415,6 +1424,7 @@ pub fn change_consensus_key( ) -> Result<()> where S: StorageRead + StorageWrite, + Gov: governance::Read, { tracing::debug!("Changing consensus key for validator {}", validator); @@ -1430,8 +1440,8 @@ where try_insert_consensus_key(storage, consensus_key)?; // Set the new consensus key at the pipeline epoch - let params = read_pos_params(storage)?; - validator_consensus_key_handle(validator).set( + let params = read_pos_params::(storage)?; + validator_consensus_key_handle(validator).set::( storage, consensus_key.clone(), current_epoch, @@ -1445,7 +1455,7 @@ where } /// Withdraw tokens from those that have been unbonded from proof-of-stake -pub fn withdraw_tokens( +pub fn withdraw_tokens( storage: &mut S, source: Option<&Address>, validator: &Address, @@ -1453,8 +1463,10 @@ pub fn withdraw_tokens( ) -> Result where S: StorageRead + StorageWrite, + Gov: governance::Read, + Token: trans_token::Write, { - let params = read_pos_params(storage)?; + let params = read_pos_params::(storage)?; let source = source.unwrap_or(validator); tracing::debug!("Withdrawing tokens in epoch {current_epoch}"); @@ -1562,7 +1574,7 @@ where // Transfer the withdrawable tokens from the PoS address back to the source let staking_token = staking_token_address(storage); - token::transfer( + Token::transfer( storage, &staking_token, &ADDRESS, @@ -1572,7 +1584,7 @@ where // TODO: Transfer the slashed tokens from the PoS address to the Slash Pool // address - // token::transfer( + // Token::transfer( // storage, // &staking_token, // &ADDRESS, @@ -1584,7 +1596,7 @@ where } /// Change the commission rate of a validator -pub fn change_validator_commission_rate( +pub fn change_validator_commission_rate( storage: &mut S, validator: &Address, new_rate: Dec, @@ -1592,6 +1604,7 @@ pub fn change_validator_commission_rate( ) -> Result<()> where S: StorageRead + StorageWrite, + Gov: governance::Read, { if new_rate.is_negative() { return Err(CommissionRateChangeError::NegativeRate( @@ -1615,7 +1628,7 @@ where CommissionRateChangeError::NoMaxSetInStorage(validator.clone()) })?; - let params = read_pos_params(storage)?; + let params = read_pos_params::(storage)?; let commission_handle = validator_commission_rate_handle(validator); let pipeline_epoch = checked!(current_epoch + params.pipeline_len)?; @@ -1642,7 +1655,12 @@ where .into()); } - commission_handle.set(storage, new_rate, current_epoch, params.pipeline_len) + commission_handle.set::( + storage, + new_rate, + current_epoch, + params.pipeline_len, + ) } fn bond_amounts_for_query( @@ -1764,15 +1782,16 @@ where /// Get the total bond amount, without applying slashes, for a given bond ID and /// epoch. For future epochs, the value is subject to change. -pub fn raw_bond_amount( +pub fn raw_bond_amount( storage: &S, bond_id: &BondId, epoch: Epoch, ) -> Result where S: StorageRead, + Gov: governance::Read, { - let params = read_pos_params(storage)?; + let params = read_pos_params::(storage)?; let amounts = bond_amounts_for_query(storage, ¶ms, bond_id, epoch)?; token::Amount::sum(amounts.values().copied()) .ok_or_err_msg("token amount overflow") @@ -1781,15 +1800,16 @@ where /// Get the total bond amount, including slashes, for a given bond ID and epoch. /// Returns the bond amount after slashing. For future epochs, the value is /// subject to change. -pub fn bond_amount( +pub fn bond_amount( storage: &S, bond_id: &BondId, epoch: Epoch, ) -> Result where S: StorageRead, + Gov: governance::Read, { - let params = read_pos_params(storage)?; + let params = read_pos_params::(storage)?; let mut amounts = bond_amounts_for_query(storage, ¶ms, bond_id, epoch)?; if !amounts.is_empty() { @@ -1857,7 +1877,7 @@ where /// the epoch in which we're calculating the bond amount to correspond to the /// validator stake that was used to calculate reward products (slashes do *not* /// retrospectively affect the rewards calculated before slash processing). -pub fn bond_amounts_for_rewards( +pub fn bond_amounts_for_rewards( storage: &S, bond_id: &BondId, claim_start: Epoch, @@ -1865,8 +1885,9 @@ pub fn bond_amounts_for_rewards( ) -> Result> where S: StorageRead, + Gov: governance::Read, { - let params = read_pos_params(storage)?; + let params = read_pos_params::(storage)?; // Outer key is every epoch in which the a bond amount contributed to stake // and the inner key is the start epoch used to calculate slashes. The inner // keys are discarded after applying slashes. @@ -1998,15 +2019,16 @@ where } /// Unjail a validator that is currently jailed. -pub fn unjail_validator( +pub fn unjail_validator( storage: &mut S, validator: &Address, current_epoch: Epoch, ) -> Result<()> where S: StorageRead + StorageWrite, + Gov: governance::Read, { - let params = read_pos_params(storage)?; + let params = read_pos_params::(storage)?; // Check that the validator is jailed up to the pipeline epoch for epoch in current_epoch.iter_range( @@ -2051,7 +2073,7 @@ where let stake = read_validator_stake(storage, ¶ms, validator, pipeline_epoch)?; - insert_validator_into_validator_set( + insert_validator_into_validator_set::( storage, ¶ms, validator, @@ -2101,7 +2123,7 @@ where } /// Redelegate bonded tokens from a source validator to a destination validator -pub fn redelegate_tokens( +pub fn redelegate_tokens( storage: &mut S, delegator: &Address, src_validator: &Address, @@ -2111,6 +2133,7 @@ pub fn redelegate_tokens( ) -> Result<()> where S: StorageRead + StorageWrite, + Gov: governance::Read, { tracing::debug!( "Delegator {} redelegating {} tokens from {} to {}", @@ -2145,7 +2168,7 @@ where ); } - let params = read_pos_params(storage)?; + let params = read_pos_params::(storage)?; let pipeline_epoch = checked!(current_epoch + params.pipeline_len)?; let src_redel_end_epoch = validator_incoming_redelegations_handle(src_validator) @@ -2175,7 +2198,7 @@ where // Unbond the redelegated tokens from the src validator. // `resultUnbond` in quint - let result_unbond = unbond_tokens( + let result_unbond = unbond_tokens::( storage, Some(delegator), src_validator, @@ -2215,7 +2238,7 @@ where if !amount_after_slashing.is_zero() { // `updatedDelegator` with updates to `bonded` let bond_handle = bond_handle(delegator, dest_validator); - bond_handle.add( + bond_handle.add::( storage, amount_after_slashing, current_epoch, @@ -2224,7 +2247,7 @@ where // `updatedDestValidator` --> `with("totalVBonded")` // Add the amount to the dest validator total bonded let dest_total_bonded = total_bonded_handle(dest_validator); - dest_total_bonded.add( + dest_total_bonded.add::( storage, amount_after_slashing, current_epoch, @@ -2297,7 +2320,7 @@ where Some(ValidatorState::Jailed) | Some(ValidatorState::Inactive) ); if !is_jailed_or_inactive_at_pipeline { - update_validator_set( + update_validator_set::( storage, ¶ms, dest_validator, @@ -2308,7 +2331,7 @@ where } // Update deltas - update_validator_deltas( + update_validator_deltas::( storage, ¶ms, dest_validator, @@ -2316,7 +2339,7 @@ where current_epoch, None, )?; - update_total_deltas( + update_total_deltas::( storage, ¶ms, amount_after_slashing.change(), @@ -2330,15 +2353,16 @@ where /// Deactivate a validator by removing it from any validator sets. A validator /// can only be deactivated if it is not jailed or already inactive. -pub fn deactivate_validator( +pub fn deactivate_validator( storage: &mut S, validator: &Address, current_epoch: Epoch, ) -> Result<()> where S: StorageRead + StorageWrite, + Gov: governance::Read, { - let params = read_pos_params(storage)?; + let params = read_pos_params::(storage)?; let pipeline_epoch = checked!(current_epoch + params.pipeline_len)?; let pipeline_state = match validator_state_handle(validator).get( @@ -2367,7 +2391,7 @@ where )?; // Promote the next below-capacity validator to consensus - promote_next_below_capacity_validator_to_consensus( + promote_next_below_capacity_validator_to_consensus::( storage, current_epoch, params.pipeline_len, @@ -2400,7 +2424,7 @@ where } // Set the state to inactive - validator_state_handle(validator).set( + validator_state_handle(validator).set::( storage, ValidatorState::Inactive, current_epoch, @@ -2411,15 +2435,16 @@ where } /// Re-activate an inactive validator -pub fn reactivate_validator( +pub fn reactivate_validator( storage: &mut S, validator: &Address, current_epoch: Epoch, ) -> Result<()> where S: StorageRead + StorageWrite, + Gov: governance::Read, { - let params = read_pos_params(storage)?; + let params = read_pos_params::(storage)?; let pipeline_epoch = checked!(current_epoch + params.pipeline_len)?; // Make sure state is Inactive at every epoch up through the pipeline @@ -2448,7 +2473,7 @@ where // discovered later, thus the validator is frozen. if is_validator_frozen(storage, validator, current_epoch, ¶ms)? { // The validator should be set back to jailed - validator_state_handle(validator).set( + validator_state_handle(validator).set::( storage, ValidatorState::Jailed, current_epoch, @@ -2461,7 +2486,7 @@ where let stake = read_validator_stake(storage, ¶ms, validator, pipeline_epoch)?; - insert_validator_into_validator_set( + insert_validator_into_validator_set::( storage, ¶ms, validator, @@ -2592,7 +2617,7 @@ where } /// Jail validators who failed to match the liveness threshold -pub fn jail_for_liveness( +pub fn jail_for_liveness( storage: &mut S, params: &PosParams, current_epoch: Epoch, @@ -2600,6 +2625,7 @@ pub fn jail_for_liveness( ) -> Result<()> where S: StorageRead + StorageWrite, + Gov: governance::Read, { // Derive the actual missing votes limit from the percentage let missing_votes_threshold = checked!( @@ -2642,175 +2668,23 @@ where validator, jail_epoch, ); - jail_validator(storage, params, validator, current_epoch, jail_epoch)?; + jail_validator::( + storage, + params, + validator, + current_epoch, + jail_epoch, + )?; } Ok(()) } -#[cfg(any(test, feature = "testing"))] -/// PoS related utility functions to help set up tests. -pub mod test_utils { - use namada_core::chain::ProposalBytes; - use namada_core::hash::Hash; - use namada_core::time::DurationSecs; - use namada_parameters::{init_storage, EpochDuration}; - use namada_trans_token::credit_tokens; - - use super::*; - use crate::types::GenesisValidator; - - /// Helper function to initialize storage with PoS data - /// about validators for tests. - pub fn init_genesis_helper( - storage: &mut S, - params: &PosParams, - validators: impl Iterator, - current_epoch: namada_core::storage::Epoch, - ) -> Result<()> - where - S: StorageRead + StorageWrite, - { - init_genesis(storage, params, current_epoch)?; - for GenesisValidator { - address, - consensus_key, - protocol_key, - eth_cold_key, - eth_hot_key, - commission_rate, - max_commission_rate_change, - tokens, - metadata, - } in validators - { - become_validator( - storage, - BecomeValidator { - params, - address: &address, - consensus_key: &consensus_key, - protocol_key: &protocol_key, - eth_cold_key: ð_cold_key, - eth_hot_key: ð_hot_key, - current_epoch, - commission_rate, - max_commission_rate_change, - metadata, - offset_opt: Some(0), - }, - )?; - // Credit token amount to be bonded to the validator address so it - // can be bonded - let staking_token = staking_token_address(storage); - credit_tokens(storage, &staking_token, &address, tokens)?; - - bond_tokens( - storage, - None, - &address, - tokens, - current_epoch, - Some(0), - )?; - } - // Store the total consensus validator stake to storage - compute_and_store_total_consensus_stake(storage, current_epoch)?; - - // Copy validator sets and positions - copy_genesis_validator_sets(storage, params, current_epoch)?; - - Ok(()) - } - - /// Init PoS genesis wrapper helper that also initializes gov params that - /// are used in PoS with default values. - pub fn test_init_genesis( - storage: &mut S, - owned: OwnedPosParams, - validators: impl Iterator + Clone, - current_epoch: namada_core::storage::Epoch, - ) -> Result - where - S: StorageRead + StorageWrite, - { - let gov_params = - namada_governance::parameters::GovernanceParameters::default(); - gov_params.init_storage(storage)?; - let params = read_non_pos_owned_params(storage, owned)?; - let chain_parameters = namada_parameters::Parameters { - max_tx_bytes: 123456789, - epoch_duration: EpochDuration { - min_num_of_blocks: 2, - min_duration: DurationSecs(4), - }, - max_proposal_bytes: ProposalBytes::default(), - max_block_gas: 10000000, - vp_allowlist: vec![], - tx_allowlist: vec![], - implicit_vp_code_hash: Some(Hash::default()), - epochs_per_year: 10000000, - masp_epoch_multiplier: 2, - masp_fee_payment_gas_limit: 10000, - gas_scale: 10_000_000, - minimum_gas_price: BTreeMap::new(), - is_native_token_transferable: true, - }; - init_storage(&chain_parameters, storage).unwrap(); - init_genesis_helper(storage, ¶ms, validators, current_epoch)?; - Ok(params) - } - - /// A dummy validator used for testing - pub fn get_dummy_genesis_validator() -> types::GenesisValidator { - use namada_core::address::testing::established_address_1; - use namada_core::key::testing::common_sk_from_simple_seed; - use namada_core::{key, token}; - - let address = established_address_1(); - let tokens = token::Amount::native_whole(1); - let consensus_sk = common_sk_from_simple_seed(0); - let consensus_key = consensus_sk.to_public(); - - let protocol_sk = common_sk_from_simple_seed(1); - let protocol_key = protocol_sk.to_public(); - - let commission_rate = - Dec::new(1, 1).expect("expected 0.1 to be a valid decimal"); - let max_commission_rate_change = - Dec::new(1, 1).expect("expected 0.1 to be a valid decimal"); - - let eth_hot_sk = - key::common::SecretKey::Secp256k1(key::testing::gen_keypair::< - key::secp256k1::SigScheme, - >()); - let eth_hot_key = eth_hot_sk.to_public(); - - let eth_cold_sk = - key::common::SecretKey::Secp256k1(key::testing::gen_keypair::< - key::secp256k1::SigScheme, - >()); - let eth_cold_key = eth_cold_sk.to_public(); - - types::GenesisValidator { - address, - tokens, - consensus_key, - protocol_key, - eth_cold_key, - eth_hot_key, - commission_rate, - max_commission_rate_change, - metadata: Default::default(), - } - } -} - /// Change validator's metadata. In addition to changing any of the data from /// [`ValidatorMetaData`], the validator's commission rate can be changed within /// here as well. #[allow(clippy::too_many_arguments)] -pub fn change_validator_metadata( +pub fn change_validator_metadata( storage: &mut S, validator: &Address, email: Option, @@ -2824,6 +2698,7 @@ pub fn change_validator_metadata( ) -> Result<()> where S: StorageRead + StorageWrite, + Gov: governance::Read, { if let Some(email) = email { write_validator_email(storage, validator, &email)?; @@ -2844,7 +2719,7 @@ where write_validator_name(storage, validator, &name)?; } if let Some(commission_rate) = commission_rate { - change_validator_commission_rate( + change_validator_commission_rate::( storage, validator, commission_rate, @@ -2856,7 +2731,7 @@ where /// Claim available rewards, triggering an immediate transfer of tokens from the /// PoS account to the source address. -pub fn claim_reward_tokens( +pub fn claim_reward_tokens( storage: &mut S, source: Option<&Address>, validator: &Address, @@ -2864,13 +2739,15 @@ pub fn claim_reward_tokens( ) -> Result where S: StorageRead + StorageWrite, + Gov: governance::Read, + Token: trans_token::Write, { tracing::debug!("Claiming rewards in epoch {current_epoch}"); let source = source.cloned().unwrap_or_else(|| validator.clone()); tracing::debug!("Source {} --> Validator {}", source, validator); - let mut reward_tokens = compute_current_rewards_from_bonds( + let mut reward_tokens = compute_current_rewards_from_bonds::( storage, &source, validator, @@ -2887,13 +2764,13 @@ where // Transfer the bonded tokens from PoS to the source let staking_token = staking_token_address(storage); - token::transfer(storage, &staking_token, &ADDRESS, &source, reward_tokens)?; + Token::transfer(storage, &staking_token, &ADDRESS, &source, reward_tokens)?; Ok(reward_tokens) } /// Query the amount of available reward tokens for a given bond. -pub fn query_reward_tokens( +pub fn query_reward_tokens( storage: &S, source: Option<&Address>, validator: &Address, @@ -2901,9 +2778,10 @@ pub fn query_reward_tokens( ) -> Result where S: StorageRead, + Gov: governance::Read, { let source = source.cloned().unwrap_or_else(|| validator.clone()); - let rewards_from_bonds = compute_current_rewards_from_bonds( + let rewards_from_bonds = compute_current_rewards_from_bonds::( storage, &source, validator, @@ -2920,7 +2798,7 @@ where /// Jail a validator by removing it from and updating the validator sets and /// changing a its state to `Jailed`. Validators are jailed for liveness and for /// misbehaving. -pub fn jail_validator( +pub fn jail_validator( storage: &mut S, params: &PosParams, validator: &Address, @@ -2929,6 +2807,7 @@ pub fn jail_validator( ) -> Result<()> where S: StorageRead + StorageWrite, + Gov: governance::Read, { tracing::debug!( "Jailing validator {} beginning in epoch {}", @@ -2961,7 +2840,7 @@ where // promote the next max inactive validator to the active // validator set at the pipeline offset if offset == params.pipeline_len { - promote_next_below_capacity_validator_to_consensus( + promote_next_below_capacity_validator_to_consensus::( storage, current_epoch, offset, @@ -3004,7 +2883,7 @@ where .expect("Safe sub cause `validator_set_update_epoch > current_epoch`"); // Set the validator state as `Jailed` thru the pipeline epoch for offset in start_offset..=params.pipeline_len { - validator_state_handle(validator).set( + validator_state_handle(validator).set::( storage, ValidatorState::Jailed, current_epoch, @@ -3015,7 +2894,7 @@ where } /// Apply PoS updates for a block -pub fn finalize_block( +pub fn finalize_block( storage: &mut S, events: &mut impl EmitEvents, is_new_epoch: bool, @@ -3025,10 +2904,11 @@ pub fn finalize_block( ) -> Result<()> where S: StorageWrite + StorageRead, + Gov: governance::Read, { let height = storage.get_block_height()?; let current_epoch = storage.get_block_epoch()?; - let pos_params = storage::read_pos_params(storage)?; + let pos_params = storage::read_pos_params::(storage)?; if is_new_epoch { // Copy the new_epoch + pipeline_len - 1 validator set into @@ -3042,14 +2922,17 @@ where // Compute the total stake of the consensus validator set and record // it in storage - compute_and_store_total_consensus_stake(storage, current_epoch)?; + compute_and_store_total_consensus_stake::( + storage, + current_epoch, + )?; } // Invariant: Has to be applied before `record_slashes_from_evidence` // because it potentially needs to be able to read validator state from // previous epoch and jailing validator removes the historical state if !votes.is_empty() { - rewards::log_block_rewards( + rewards::log_block_rewards::( storage, votes.clone(), height, @@ -3060,7 +2943,7 @@ where // Invariant: This has to be applied after // `copy_validator_sets_and_positions` and before `self.update_epoch`. - slashing::record_slashes_from_evidence( + slashing::record_slashes_from_evidence::( storage, byzantine_validators, &pos_params, @@ -3077,7 +2960,7 @@ where // Process and apply slashes that have already been recorded for the // current epoch if let Err(err) = - slashing::process_slashes(storage, events, current_epoch) + slashing::process_slashes::(storage, events, current_epoch) { tracing::error!( "Error while processing slashes queued for epoch {}: {}", @@ -3107,7 +2990,7 @@ where } // Jail validators for inactivity - jail_for_liveness( + jail_for_liveness::( storage, &pos_params, current_epoch, @@ -3217,3 +3100,171 @@ fn prune_old_delegations( Ok(()) } + +#[cfg(any(test, feature = "testing"))] +/// PoS related utility functions to help set up tests. +pub mod test_utils { + use namada_core::chain::ProposalBytes; + use namada_core::hash::Hash; + use namada_core::parameters::EpochDuration; + use namada_core::time::DurationSecs; + + use super::*; + use crate::types::GenesisValidator; + + /// Helper function to initialize storage with PoS data + /// about validators for tests. + pub fn init_genesis_helper( + storage: &mut S, + params: &PosParams, + validators: impl Iterator, + current_epoch: namada_core::storage::Epoch, + ) -> Result<()> + where + S: StorageRead + StorageWrite, + Gov: governance::Read, + Token: trans_token::Write, + { + init_genesis(storage, params, current_epoch)?; + for GenesisValidator { + address, + consensus_key, + protocol_key, + eth_cold_key, + eth_hot_key, + commission_rate, + max_commission_rate_change, + tokens, + metadata, + } in validators + { + become_validator::( + storage, + BecomeValidator { + params, + address: &address, + consensus_key: &consensus_key, + protocol_key: &protocol_key, + eth_cold_key: ð_cold_key, + eth_hot_key: ð_hot_key, + current_epoch, + commission_rate, + max_commission_rate_change, + metadata, + offset_opt: Some(0), + }, + )?; + // Credit token amount to be bonded to the validator address so it + // can be bonded + let staking_token = staking_token_address(storage); + Token::credit_tokens(storage, &staking_token, &address, tokens)?; + + bond_tokens::( + storage, + None, + &address, + tokens, + current_epoch, + Some(0), + )?; + } + // Store the total consensus validator stake to storage + compute_and_store_total_consensus_stake::( + storage, + current_epoch, + )?; + + // Copy validator sets and positions + copy_genesis_validator_sets::(storage, params, current_epoch)?; + + Ok(()) + } + + /// Init PoS genesis wrapper helper that also initializes gov params that + /// are used in PoS with default values. + pub fn test_init_genesis( + storage: &mut S, + owned: OwnedPosParams, + validators: impl Iterator + Clone, + current_epoch: namada_core::storage::Epoch, + ) -> Result + where + S: StorageRead + StorageWrite, + Params: namada_systems::parameters::Write, + Gov: governance::Write, + Token: trans_token::Write, + { + Gov::init_default_params(storage)?; + let params = read_non_pos_owned_params::<_, Gov>(storage, owned)?; + let chain_parameters = namada_core::parameters::Parameters { + max_tx_bytes: 123456789, + epoch_duration: EpochDuration { + min_num_of_blocks: 2, + min_duration: DurationSecs(4), + }, + max_proposal_bytes: ProposalBytes::default(), + max_block_gas: 10000000, + vp_allowlist: vec![], + tx_allowlist: vec![], + implicit_vp_code_hash: Some(Hash::default()), + epochs_per_year: 10000000, + masp_epoch_multiplier: 2, + masp_fee_payment_gas_limit: 10000, + gas_scale: 100_000_000, + minimum_gas_price: BTreeMap::new(), + is_native_token_transferable: true, + }; + Params::write(storage, &chain_parameters).unwrap(); + init_genesis_helper::( + storage, + ¶ms, + validators, + current_epoch, + )?; + Ok(params) + } + + /// A dummy validator used for testing + pub fn get_dummy_genesis_validator() -> types::GenesisValidator { + use namada_core::address::testing::established_address_1; + use namada_core::key; + use namada_core::key::testing::common_sk_from_simple_seed; + + let address = established_address_1(); + let tokens = token::Amount::native_whole(1); + let consensus_sk = common_sk_from_simple_seed(0); + let consensus_key = consensus_sk.to_public(); + + let protocol_sk = common_sk_from_simple_seed(1); + let protocol_key = protocol_sk.to_public(); + + let commission_rate = + Dec::new(1, 1).expect("expected 0.1 to be a valid decimal"); + let max_commission_rate_change = + Dec::new(1, 1).expect("expected 0.1 to be a valid decimal"); + + let eth_hot_sk = + key::common::SecretKey::Secp256k1(key::testing::gen_keypair::< + key::secp256k1::SigScheme, + >()); + let eth_hot_key = eth_hot_sk.to_public(); + + let eth_cold_sk = + key::common::SecretKey::Secp256k1(key::testing::gen_keypair::< + key::secp256k1::SigScheme, + >()); + let eth_cold_key = eth_cold_sk.to_public(); + + types::GenesisValidator { + address, + tokens, + consensus_key, + protocol_key, + eth_cold_key, + eth_hot_key, + commission_rate, + max_commission_rate_change, + metadata: Default::default(), + } + } +} diff --git a/crates/proof_of_stake/src/parameters.rs b/crates/proof_of_stake/src/parameters.rs index af15a10b266..6d63529f063 100644 --- a/crates/proof_of_stake/src/parameters.rs +++ b/crates/proof_of_stake/src/parameters.rs @@ -8,6 +8,7 @@ use namada_core::dec::Dec; use namada_core::storage::Epoch; use namada_core::token; use namada_core::uint::Uint; +#[cfg(test)] use namada_governance::parameters::GovernanceParameters; use namada_macros::BorshDeserializer; #[cfg(feature = "migrations")] @@ -106,6 +107,7 @@ impl Default for OwnedPosParams { } } +#[cfg(test)] impl Default for PosParams { fn default() -> Self { let owned = OwnedPosParams::default(); @@ -269,7 +271,7 @@ impl OwnedPosParams { } /// A test helper to add the default gov params to PoS params. - #[cfg(any(test, feature = "testing"))] + #[cfg(test)] pub fn with_default_gov_params(self) -> PosParams { let gov = GovernanceParameters::default(); PosParams { @@ -279,7 +281,7 @@ impl OwnedPosParams { } /// A test helper to add the default gov params to PoS params. - #[cfg(any(test, feature = "testing"))] + #[cfg(test)] pub fn with_gov_params(self, gov: &GovernanceParameters) -> PosParams { PosParams { owned: self, diff --git a/crates/proof_of_stake/src/pos_queries.rs b/crates/proof_of_stake/src/pos_queries.rs deleted file mode 100644 index 74964350813..00000000000 --- a/crates/proof_of_stake/src/pos_queries.rs +++ /dev/null @@ -1,291 +0,0 @@ -//! Storage API for querying data about Proof-of-stake related -//! data. This includes validator and epoch related data. - -use namada_core::address::Address; -use namada_core::chain::ProposalBytes; -use namada_core::storage::{BlockHeight, Epoch}; -use namada_core::{key, token}; -use namada_parameters::storage::get_max_proposal_bytes_key; -use namada_storage::collections::lazy_map::NestedSubKey; -use namada_storage::StorageRead; -use thiserror::Error; - -use crate::storage::find_validator_by_raw_hash; -use crate::types::WeightedValidator; -use crate::{ - consensus_validator_set_handle, get_total_consensus_stake, read_pos_params, - validator_eth_cold_key_handle, validator_eth_hot_key_handle, - ConsensusValidatorSet, PosParams, -}; - -/// Errors returned by [`PosQueries`] operations. -#[derive(Error, Debug)] -pub enum Error { - /// A storage error occurred. - #[error("Storage error: {0}")] - Storage(#[from] namada_storage::Error), - /// The given address is not among the set of consensus validators for - /// the corresponding epoch. - #[error( - "The address '{0:?}' is not among the consensus validator set for \ - epoch {1}" - )] - NotValidatorAddress(Address, Epoch), - /// The given public key does not correspond to any consensus validator's - /// key at the provided epoch. - #[error( - "The public key '{0}' is not among the consensus validator set for \ - epoch {1}" - )] - NotValidatorKey(String, Epoch), - /// The given public key hash does not correspond to any consensus - /// validator's key at the provided epoch. - #[error( - "The public key hash '{0}' does not belong to a validator in storage" - )] - NotValidatorKeyHash(String), -} - -/// Result type returned by [`PosQueries`] operations. -pub type Result = ::std::result::Result; - -/// Methods used to query blockchain proof-of-stake related state, -/// such as the current set of consensus validators. -pub trait PosQueries { - /// The underlying storage type. - type Storage; - - /// Return a handle to [`PosQueries`]. - fn pos_queries(&self) -> PosQueriesHook<'_, Self::Storage>; -} - -impl PosQueries for S -where - S: StorageRead, -{ - type Storage = Self; - - #[inline] - fn pos_queries(&self) -> PosQueriesHook<'_, Self> { - PosQueriesHook { storage: self } - } -} - -/// A handle to [`PosQueries`]. -/// -/// This type is a wrapper around a pointer to a [`impl ReadStorage`]. -#[derive(Debug)] -#[repr(transparent)] -pub struct PosQueriesHook<'db, S> { - storage: &'db S, -} - -impl<'db, S> Clone for PosQueriesHook<'db, S> { - fn clone(&self) -> Self { - *self - } -} - -impl<'db, S> Copy for PosQueriesHook<'db, S> {} - -impl<'db, S> PosQueriesHook<'db, S> -where - S: StorageRead, -{ - /// Return a handle to the inner storage. - #[inline] - pub fn storage(self) -> &'db S { - self.storage - } - - /// Read the proof-of-stake parameters from storage. - pub fn get_pos_params(self) -> PosParams { - read_pos_params(self.storage) - .expect("Should be able to read PosParams from storage") - } - - /// Get the set of consensus validators for a given epoch (defaulting to the - /// epoch of the current yet-to-be-committed block). - #[inline] - pub fn get_consensus_validators( - self, - epoch: Option, - ) -> ConsensusValidators<'db, S> { - let epoch = - epoch.unwrap_or_else(|| self.storage.get_block_epoch().unwrap()); - ConsensusValidators { - state: self.storage, - validator_set: consensus_validator_set_handle().at(&epoch), - } - } - - /// Lookup the total voting power for an epoch (defaulting to the - /// epoch of the current yet-to-be-committed block). - pub fn get_total_voting_power(self, epoch: Option) -> token::Amount { - let epoch = - epoch.unwrap_or_else(|| self.storage.get_block_epoch().unwrap()); - let pos_params = self.get_pos_params(); - get_total_consensus_stake(self.storage, epoch, &pos_params) - // NB: the only reason this call should fail is if we request - // an epoch that hasn't been reached yet. let's "fail" by - // returning a total stake of 0 NAM - .unwrap_or_default() - } - - /// Lookup data about a validator from their protocol signing key. - pub fn get_validator_from_protocol_pk( - self, - pk: &key::common::PublicKey, - epoch: Option, - ) -> Result { - let params = crate::read_pos_params(self.storage) - .expect("Failed to fetch Pos params"); - let epoch = epoch - .map(Ok) - .unwrap_or_else(|| self.storage.get_block_epoch())?; - self.get_consensus_validators(Some(epoch)) - .iter() - .find(|validator| { - let protocol_keys = - crate::validator_protocol_key_handle(&validator.address); - match protocol_keys.get(self.storage, epoch, ¶ms) { - Ok(Some(key)) => key == *pk, - _ => false, - } - }) - .ok_or_else(|| Error::NotValidatorKey(pk.to_string(), epoch)) - } - - /// Lookup data about a validator from their address. - pub fn get_validator_from_address( - self, - address: &Address, - epoch: Option, - ) -> Result<(token::Amount, key::common::PublicKey)> { - let params = crate::read_pos_params(self.storage) - .expect("Failed to fetch Pos params"); - let epoch = epoch - .map(Ok) - .unwrap_or_else(|| self.storage.get_block_epoch())?; - self.get_consensus_validators(Some(epoch)) - .iter() - .find(|validator| address == &validator.address) - .map(|validator| { - let protocol_keys = - crate::validator_protocol_key_handle(&validator.address); - let protocol_pk = protocol_keys - .get(self.storage, epoch, ¶ms) - .unwrap() - .expect( - "Protocol public key should be set in storage after \ - genesis.", - ); - - (validator.bonded_stake, protocol_pk) - }) - .ok_or_else(|| Error::NotValidatorAddress(address.clone(), epoch)) - } - - /// Given a tendermint validator, the address is the hash - /// of the validators public key. We look up the native - /// address from storage using this hash. - pub fn get_validator_from_tm_address( - self, - tm_address: impl AsRef, - ) -> Result
{ - let addr_hash = tm_address.as_ref(); - let validator = find_validator_by_raw_hash(self.storage, addr_hash) - .map_err(Error::Storage)?; - validator.ok_or_else(|| Error::NotValidatorKeyHash(addr_hash.into())) - } - - /// Given some [`BlockHeight`], return the corresponding [`Epoch`]. - /// - /// This method may return [`None`] if the corresponding data has - /// been purged from Namada, or if it is not available yet. - #[inline] - pub fn get_epoch(self, height: BlockHeight) -> Option { - self.storage.get_epoch_at_height(height).unwrap() - } - - /// Retrieve the `max_proposal_bytes` consensus parameter from storage. - pub fn get_max_proposal_bytes(self) -> ProposalBytes { - namada_storage::StorageRead::read( - self.storage, - &get_max_proposal_bytes_key(), - ) - .expect("Must be able to read ProposalBytes from storage") - .expect("ProposalBytes must be present in storage") - } - - /// Get a validator's Ethereum hot key from storage, at the given epoch, or - /// the last one, if none is provided. - pub fn read_validator_eth_hot_key( - self, - validator: &Address, - epoch: Option, - ) -> Option { - let epoch = - epoch.unwrap_or_else(|| self.storage.get_block_epoch().unwrap()); - let params = self.get_pos_params(); - validator_eth_hot_key_handle(validator) - .get(self.storage, epoch, ¶ms) - .ok() - .flatten() - } - - /// Get a validator's Ethereum cold key from storage, at the given epoch, or - /// the last one, if none is provided. - pub fn read_validator_eth_cold_key( - self, - validator: &Address, - epoch: Option, - ) -> Option { - let epoch = - epoch.unwrap_or_else(|| self.storage.get_block_epoch().unwrap()); - let params = self.get_pos_params(); - validator_eth_cold_key_handle(validator) - .get(self.storage, epoch, ¶ms) - .ok() - .flatten() - } -} - -/// A handle to the set of consensus validators in Namada, -/// at some given epoch. -pub struct ConsensusValidators<'db, S> -where - S: StorageRead, -{ - state: &'db S, - validator_set: ConsensusValidatorSet, -} - -impl<'db, S> ConsensusValidators<'db, S> -where - S: StorageRead, -{ - /// Iterate over the set of consensus validators in Namada, at some given - /// epoch. - pub fn iter<'this: 'db>( - &'this self, - ) -> impl Iterator + 'db { - self.validator_set - .iter(self.state) - .expect("Must be able to iterate over consensus validators") - .map(|res| { - let ( - NestedSubKey::Data { - key: bonded_stake, .. - }, - address, - ) = res.expect( - "We should be able to decode validators in storage", - ); - WeightedValidator { - address, - bonded_stake, - } - }) - } -} diff --git a/crates/proof_of_stake/src/queries.rs b/crates/proof_of_stake/src/queries.rs index 0926ed589d4..626adf87f3e 100644 --- a/crates/proof_of_stake/src/queries.rs +++ b/crates/proof_of_stake/src/queries.rs @@ -7,14 +7,18 @@ use borsh::BorshDeserialize; use namada_core::address::Address; use namada_core::collections::{HashMap, HashSet}; use namada_core::dec::Dec; +use namada_core::key::common; use namada_core::storage::Epoch; use namada_core::token; use namada_storage::collections::lazy_map::{NestedSubKey, SubKey}; use namada_storage::StorageRead; +use namada_systems::governance; use crate::slashing::{find_validator_slashes, get_slashed_amount}; use crate::storage::{ - bond_handle, delegation_targets_handle, read_pos_params, unbond_handle, + bond_handle, delegation_targets_handle, + read_consensus_validator_set_addresses, read_pos_params, unbond_handle, + validator_eth_hot_key_handle, }; use crate::types::{ BondDetails, BondId, BondsAndUnbondsDetail, BondsAndUnbondsDetails, @@ -77,13 +81,14 @@ where /// Find all validators to which a given bond `owner` (or source) has a /// delegation with the amount -pub fn find_delegations( +pub fn find_delegations( storage: &S, owner: &Address, epoch: &Epoch, ) -> namada_storage::Result> where S: StorageRead, + Gov: governance::Read, { let validators = delegation_targets_handle(owner); if validators.is_empty(storage)? { @@ -101,7 +106,7 @@ where }, ) = validator?; - let bond_amount = raw_bond_amount( + let bond_amount = raw_bond_amount::( storage, &BondId { source: owner.clone(), @@ -138,15 +143,16 @@ where } /// Find if the given source address has any bonds. -pub fn has_bonds( +pub fn has_bonds( storage: &S, source: &Address, ) -> namada_storage::Result where S: StorageRead, + Gov: governance::Read, { let max_epoch = Epoch(u64::MAX); - let delegations = find_delegations(storage, source, &max_epoch)?; + let delegations = find_delegations::(storage, source, &max_epoch)?; Ok(!delegations.values().all(token::Amount::is_zero)) } @@ -192,15 +198,16 @@ where /// Collect the details of all bonds and unbonds that match the source and /// validator arguments. If either source or validator is `None`, then grab the /// information for all sources or validators, respectively. -pub fn bonds_and_unbonds( +pub fn bonds_and_unbonds( storage: &S, source: Option
, validator: Option
, ) -> namada_storage::Result where S: StorageRead, + Gov: governance::Read, { - let params = read_pos_params(storage)?; + let params = read_pos_params::(storage)?; match (source.clone(), validator.clone()) { (Some(source), Some(validator)) => { @@ -527,3 +534,92 @@ fn make_unbond_details( slashed_amount, } } + +/// Lookup the total voting power for an epoch. +pub fn get_total_voting_power( + storage: &S, + epoch: Epoch, +) -> token::Amount +where + S: StorageRead, + Gov: governance::Read, +{ + let params = + read_pos_params::(storage).expect("PoS params must be present"); + crate::get_total_consensus_stake(storage, epoch, ¶ms) + .expect("Total consensus stake must always be available") +} + +/// Find the protocol key of the given validator address at the given epoch. +pub fn get_validator_protocol_key( + storage: &S, + addr: &Address, + epoch: Epoch, +) -> namada_storage::Result> +where + S: StorageRead, + Gov: governance::Read, +{ + let params = + read_pos_params::(storage).expect("PoS params must be present"); + let protocol_keys = crate::validator_protocol_key_handle(addr); + protocol_keys.get(storage, epoch, ¶ms) +} + +/// Get a validator's Ethereum hot key from storage at the given epoch. +pub fn get_validator_eth_hot_key( + storage: &S, + validator: &Address, + epoch: Epoch, +) -> namada_storage::Result> +where + S: StorageRead, + Gov: governance::Read, +{ + let params = + read_pos_params::(storage).expect("PoS params must be present"); + validator_eth_hot_key_handle(validator).get(storage, epoch, ¶ms) +} + +/// Read PoS validator's stake (sum of deltas). +/// For non-validators and validators with `0` stake, this returns the default - +/// `token::Amount::zero()`. +pub fn read_validator_stake( + storage: &S, + validator: &Address, + epoch: Epoch, +) -> namada_storage::Result +where + S: StorageRead, + Gov: governance::Read, +{ + let params = + read_pos_params::(storage).expect("PoS params must be present"); + crate::storage::read_validator_stake(storage, ¶ms, validator, epoch) +} + +/// Lookup data about a validator from their protocol signing key. +pub fn get_consensus_validator_from_protocol_pk( + storage: &S, + pk: &common::PublicKey, + epoch: Option, +) -> namada_storage::Result> +where + S: StorageRead, + Gov: governance::Read, +{ + let params = crate::read_pos_params::(storage)?; + let epoch = epoch.map(Ok).unwrap_or_else(|| storage.get_block_epoch())?; + + let address = read_consensus_validator_set_addresses(storage, epoch)? + .iter() + .find(|validator| { + let protocol_keys = crate::validator_protocol_key_handle(validator); + match protocol_keys.get(storage, epoch, ¶ms) { + Ok(Some(key)) => key == *pk, + _ => false, + } + }) + .cloned(); + Ok(address) +} diff --git a/crates/proof_of_stake/src/rewards.rs b/crates/proof_of_stake/src/rewards.rs index 6ad8783bf5e..7634469c002 100644 --- a/crates/proof_of_stake/src/rewards.rs +++ b/crates/proof_of_stake/src/rewards.rs @@ -6,12 +6,11 @@ use namada_core::arith::{self, checked}; use namada_core::collections::{HashMap, HashSet}; use namada_core::dec::Dec; use namada_core::storage::{BlockHeight, Epoch}; -use namada_core::token::{self, Amount}; +use namada_core::token; use namada_core::uint::{Uint, I256}; -use namada_parameters::storage as params_storage; use namada_storage::collections::lazy_map::NestedSubKey; use namada_storage::{ResultExt, StorageRead, StorageWrite}; -use namada_trans_token::get_effective_total_native_supply; +use namada_systems::{governance, parameters, trans_token}; use thiserror::Error; use crate::storage::{ @@ -22,7 +21,6 @@ use crate::storage::{ validator_state_handle, write_last_pos_inflation_amount, write_last_staked_ratio, }; -use crate::token::credit_tokens; use crate::types::{into_tm_voting_power, BondId, ValidatorState, VoteInfo}; use crate::{ bond_amounts_for_rewards, get_total_consensus_stake, staking_token_address, @@ -109,9 +107,9 @@ pub struct PosRewardsCalculator { /// Rewards fraction that goes to the block signers pub signer_reward: Dec, /// Total stake of validators who signed the block - pub signing_stake: Amount, + pub signing_stake: token::Amount, /// Total stake of the whole consensus set - pub total_stake: Amount, + pub total_stake: token::Amount, } impl PosRewardsCalculator { @@ -158,7 +156,7 @@ impl PosRewardsCalculator { } /// Implement as ceiling of (2/3) * validator set stake - fn get_min_required_votes(&self) -> Amount { + fn get_min_required_votes(&self) -> token::Amount { (self .total_stake .checked_mul(2_u64) @@ -171,7 +169,7 @@ impl PosRewardsCalculator { } /// Process the proposer and votes in the block to assign their PoS rewards. -pub(crate) fn log_block_rewards( +pub(crate) fn log_block_rewards( storage: &mut S, votes: Vec, height: BlockHeight, @@ -180,13 +178,14 @@ pub(crate) fn log_block_rewards( ) -> namada_storage::Result<()> where S: StorageWrite + StorageRead, + Gov: governance::Read, { // Read the block proposer of the previously committed block in storage // (n-1 if we are in the process of finalizing n right now). match storage::read_last_block_proposer_address(storage)? { Some(proposer_address) => { tracing::debug!("Found last block proposer: {proposer_address}"); - log_block_rewards_aux( + log_block_rewards_aux::( storage, if new_epoch { current_epoch.prev().expect("New epoch must have prev") @@ -213,7 +212,7 @@ where /// Tally a running sum of the fraction of rewards owed to each validator in /// the consensus set. This is used to keep track of the rewards due to each /// consensus validator over the lifetime of an epoch. -pub(crate) fn log_block_rewards_aux( +pub(crate) fn log_block_rewards_aux( storage: &mut S, epoch: impl Into, proposer_address: &Address, @@ -221,12 +220,13 @@ pub(crate) fn log_block_rewards_aux( ) -> namada_storage::Result<()> where S: StorageRead + StorageWrite, + Gov: governance::Read, { // The votes correspond to the last committed block (n-1 if we are // finalizing block n) let epoch: Epoch = epoch.into(); - let params = read_pos_params(storage)?; + let params = read_pos_params::(storage)?; let consensus_validators = consensus_validator_set_handle().at(&epoch); // Get total stake of the consensus validator set @@ -355,24 +355,25 @@ where } /// Apply inflation to the Proof of Stake system. -pub fn apply_inflation( +pub fn apply_inflation( storage: &mut S, last_epoch: Epoch, num_blocks_in_last_epoch: u64, ) -> namada_storage::Result<()> where S: StorageRead + StorageWrite, + Gov: governance::Read, + Parameters: parameters::Read, + Token: trans_token::Read + trans_token::Write, { // Read from Parameters storage - let epochs_per_year: u64 = storage - .read(¶ms_storage::get_epochs_per_year_key())? - .expect("Epochs per year should exist in parameters storage"); + let epochs_per_year: u64 = Parameters::epochs_per_year(storage)?; let staking_token = staking_token_address(storage); - let total_tokens = get_effective_total_native_supply(storage)?; + let total_tokens = Token::get_effective_total_native_supply(storage)?; // Read from PoS storage - let params = read_pos_params(storage)?; + let params = read_pos_params::(storage)?; let locked_amount = read_total_stake(storage, ¶ms, last_epoch)?; let last_staked_ratio = read_last_staked_ratio(storage)? @@ -400,7 +401,7 @@ where // Mint inflation and partition rewards among all accounts that earn a // portion of it - update_rewards_products_and_mint_inflation( + update_rewards_products_and_mint_inflation::( storage, ¶ms, last_epoch, @@ -432,7 +433,7 @@ struct Rewards { /// tokens into the PoS account. /// Any left-over inflation tokens from rounding error of the sum of the /// rewards is given to the governance address. -pub fn update_rewards_products_and_mint_inflation( +pub fn update_rewards_products_and_mint_inflation( storage: &mut S, params: &PosParams, last_epoch: Epoch, @@ -443,6 +444,7 @@ pub fn update_rewards_products_and_mint_inflation( ) -> namada_storage::Result<()> where S: StorageRead + StorageWrite, + Token: trans_token::Write, { // Read the rewards accumulator and calculate the new rewards products // for the previous epoch @@ -519,7 +521,12 @@ where inflation.to_string_native(), total_native_tokens.to_string_native(), ); - credit_tokens(storage, staking_token, &address::POS, pos_reward_tokens)?; + Token::credit_tokens( + storage, + staking_token, + &address::POS, + pos_reward_tokens, + )?; if reward_tokens_remaining > token::Amount::zero() { tracing::info!( @@ -527,7 +534,7 @@ where Governance account. Amount: {}.", reward_tokens_remaining.to_string_native() ); - credit_tokens( + Token::credit_tokens( storage, staking_token, &address::PGF, @@ -547,7 +554,7 @@ where /// Compute the current available rewards amount due only to existing bonds. /// This does not include pending rewards held in the rewards counter due to /// unbonds and redelegations. -pub fn compute_current_rewards_from_bonds( +pub fn compute_current_rewards_from_bonds( storage: &S, source: &Address, validator: &Address, @@ -555,6 +562,7 @@ pub fn compute_current_rewards_from_bonds( ) -> namada_storage::Result where S: StorageRead, + Gov: governance::Read, { if current_epoch == Epoch::default() { // Nothing to claim in the first epoch @@ -580,7 +588,7 @@ where .prev() .expect("Safe because of the check above"), ); - let bond_amounts = bond_amounts_for_rewards( + let bond_amounts = bond_amounts_for_rewards::( storage, &BondId { source: source.clone(), diff --git a/crates/proof_of_stake/src/slashing.rs b/crates/proof_of_stake/src/slashing.rs index 071c0a23f7b..5ce05e1f1d2 100644 --- a/crates/proof_of_stake/src/slashing.rs +++ b/crates/proof_of_stake/src/slashing.rs @@ -18,6 +18,7 @@ use namada_storage::collections::lazy_map::{ }; use namada_storage::collections::LazyMap; use namada_storage::{OptionExt, ResultExt, StorageRead, StorageWrite}; +use namada_systems::governance; use crate::event::PosEvent; use crate::storage::{ @@ -41,7 +42,7 @@ use crate::{ }; /// Apply PoS slashes from the evidence -pub(crate) fn record_slashes_from_evidence( +pub(crate) fn record_slashes_from_evidence( storage: &mut S, byzantine_validators: Vec, pos_params: &PosParams, @@ -50,6 +51,7 @@ pub(crate) fn record_slashes_from_evidence( ) -> namada_storage::Result<()> where S: StorageWrite + StorageRead, + Gov: governance::Read, { if !byzantine_validators.is_empty() { let pred_epochs = storage.get_pred_epochs()?; @@ -118,7 +120,7 @@ where evidence_height, current_epoch ); - if let Err(err) = slash( + if let Err(err) = slash::( storage, pos_params, current_epoch, @@ -139,7 +141,7 @@ where /// then jail the validator, removing it from the validator set. The slash rate /// will be computed at a later epoch. #[allow(clippy::too_many_arguments)] -pub fn slash( +pub fn slash( storage: &mut S, params: &PosParams, current_epoch: Epoch, @@ -151,6 +153,7 @@ pub fn slash( ) -> namada_storage::Result<()> where S: StorageRead + StorageWrite, + Gov: governance::Read, { let evidence_block_height: u64 = evidence_block_height.into(); let slash = Slash { @@ -184,7 +187,7 @@ where } // Jail the validator and update validator sets - jail_validator( + jail_validator::( storage, params, validator, @@ -203,15 +206,16 @@ where /// cubic slashing rate is computed. Then, each slash is recorded in storage /// along with its computed rate, and stake is deducted from the affected /// validators. -pub fn process_slashes( +pub fn process_slashes( storage: &mut S, events: &mut impl EmitEvents, current_epoch: Epoch, ) -> namada_storage::Result<()> where S: StorageRead + StorageWrite, + Gov: governance::Read, { - let params = read_pos_params(storage)?; + let params = read_pos_params::(storage)?; if current_epoch.0 < params.slash_processing_epoch_offset() { return Ok(()); @@ -316,7 +320,7 @@ where ValidatorState::Jailed | ValidatorState::Inactive ); if !is_jailed_or_inactive { - update_validator_set( + update_validator_set::( storage, ¶ms, &validator, @@ -337,7 +341,7 @@ where checked!(slash_acc += slash_delta)?; let neg_slash_delta = checked!(-slash_delta.change())?; - update_validator_deltas( + update_validator_deltas::( storage, ¶ms, &validator, @@ -352,7 +356,7 @@ where .unwrap(), ValidatorState::Jailed | ValidatorState::Inactive ); - update_total_deltas( + update_total_deltas::( storage, ¶ms, neg_slash_delta, diff --git a/crates/proof_of_stake/src/storage.rs b/crates/proof_of_stake/src/storage.rs index 081f6c06ac6..981506c30fc 100644 --- a/crates/proof_of_stake/src/storage.rs +++ b/crates/proof_of_stake/src/storage.rs @@ -11,10 +11,10 @@ use namada_core::dec::Dec; use namada_core::key::{common, tm_consensus_key_raw_hash}; use namada_core::storage::Epoch; use namada_core::token; -use namada_governance::storage::get_max_proposal_period; use namada_storage::collections::lazy_map::NestedSubKey; use namada_storage::collections::{LazyCollection, LazySet}; use namada_storage::{Result, StorageRead, StorageWrite}; +use namada_systems::governance; use crate::storage_key::consensus_keys_key; use crate::types::{ @@ -272,24 +272,26 @@ where } /// Read PoS parameters -pub fn read_pos_params(storage: &S) -> namada_storage::Result +pub fn read_pos_params(storage: &S) -> namada_storage::Result where S: StorageRead, + Gov: governance::Read, { let params = read_owned_pos_params(storage)?; - read_non_pos_owned_params(storage, params) + read_non_pos_owned_params::(storage, params) } /// Read non-PoS-owned parameters to add them to `OwnedPosParams` to construct /// `PosParams`. -pub fn read_non_pos_owned_params( +pub fn read_non_pos_owned_params( storage: &S, owned: OwnedPosParams, ) -> namada_storage::Result where S: StorageRead, + Gov: governance::Read, { - let max_proposal_period = get_max_proposal_period(storage)?; + let max_proposal_period = Gov::max_proposal_period(storage)?; Ok(PosParams { owned, max_proposal_period, @@ -456,15 +458,16 @@ where } /// Read the validator state -pub fn read_validator_state( +pub fn read_validator_state( storage: &S, validator: &Address, epoch: &Epoch, ) -> namada_storage::Result> where S: StorageRead, + Gov: governance::Read, { - let params = read_pos_params(storage)?; + let params = read_pos_params::(storage)?; validator_state_handle(validator).get(storage, *epoch, ¶ms) } @@ -505,7 +508,7 @@ where } /// Add or remove PoS validator's stake delta value -pub fn update_validator_deltas( +pub fn update_validator_deltas( storage: &mut S, params: &OwnedPosParams, validator: &Address, @@ -515,6 +518,7 @@ pub fn update_validator_deltas( ) -> namada_storage::Result<()> where S: StorageRead + StorageWrite, + Gov: governance::Read, { let handle = validator_deltas_handle(validator); let offset = offset_opt.unwrap_or(params.pipeline_len); @@ -522,7 +526,7 @@ where let val = handle .get_delta_val(storage, offset_epoch)? .unwrap_or_default(); - handle.set( + handle.set::( storage, val.checked_add(delta) .expect("Validator deltas updated amount should not overflow"), @@ -602,14 +606,15 @@ where } /// Read all addresses from the below-threshold set -pub fn read_below_threshold_validator_set_addresses( +pub fn read_below_threshold_validator_set_addresses( storage: &S, epoch: namada_core::storage::Epoch, ) -> namada_storage::Result> where S: StorageRead, + Gov: governance::Read, { - let params = read_pos_params(storage)?; + let params = read_pos_params::(storage)?; Ok(validator_addresses_handle() .at(&epoch) .iter(storage)? @@ -713,7 +718,7 @@ where /// Update PoS total deltas. /// Note: for EpochedDelta, write the value to change storage by -pub fn update_total_deltas( +pub fn update_total_deltas( storage: &mut S, params: &OwnedPosParams, delta: token::Change, @@ -723,6 +728,7 @@ pub fn update_total_deltas( ) -> namada_storage::Result<()> where S: StorageRead + StorageWrite, + Gov: governance::Read, { let offset = offset_opt.unwrap_or(params.pipeline_len); let total_deltas = total_deltas_handle(); @@ -733,7 +739,7 @@ where let total_deltas_val = total_deltas .get_delta_val(storage, offset_epoch)? .unwrap_or_default(); - total_deltas.set( + total_deltas.set::( storage, total_deltas_val .checked_add(delta) @@ -747,7 +753,7 @@ where let active_delta = total_active_deltas .get_delta_val(storage, offset_epoch)? .unwrap_or_default(); - total_active_deltas.set( + total_active_deltas.set::( storage, active_delta.checked_add(delta).expect( "Total active voting power updated amount should not overflow", @@ -1034,14 +1040,15 @@ where } /// Find a consensus key of a validator account. -pub fn get_consensus_key( +pub fn get_consensus_key( storage: &S, addr: &Address, epoch: Epoch, ) -> namada_storage::Result> where S: StorageRead, + Gov: governance::Read, { - let params = read_pos_params(storage)?; + let params = read_pos_params::(storage)?; validator_consensus_key_handle(addr).get(storage, epoch, ¶ms) } diff --git a/crates/proof_of_stake/src/tests/helpers.rs b/crates/proof_of_stake/src/tests/helpers.rs index 2589d388692..aa6dece63b3 100644 --- a/crates/proof_of_stake/src/tests/helpers.rs +++ b/crates/proof_of_stake/src/tests/helpers.rs @@ -16,6 +16,7 @@ use namada_state::testing::TestState; use proptest::prop_oneof; use proptest::strategy::{Just, Strategy}; +use super::GovStore; use crate::parameters::testing::arb_pos_params; use crate::types::{GenesisValidator, ValidatorSetUpdate}; use crate::validator_set_update::{ @@ -68,7 +69,8 @@ pub fn get_tendermint_set_updates( pub fn advance_epoch(s: &mut TestState, params: &PosParams) -> Epoch { s.in_mem_mut().block.epoch = s.in_mem().block.epoch.next(); let current_epoch = s.in_mem().block.epoch; - compute_and_store_total_consensus_stake(s, current_epoch).unwrap(); + compute_and_store_total_consensus_stake::<_, GovStore<_>>(s, current_epoch) + .unwrap(); copy_validator_sets_and_positions( s, params, diff --git a/crates/proof_of_stake/src/tests/mod.rs b/crates/proof_of_stake/src/tests/mod.rs index 86cb3d6ca11..6bf69e74c13 100644 --- a/crates/proof_of_stake/src/tests/mod.rs +++ b/crates/proof_of_stake/src/tests/mod.rs @@ -1,3 +1,14 @@ +use namada_core::address::Address; +use namada_core::collections::{HashMap, HashSet}; +use namada_core::key::common; +use namada_events::EmitEvents; +use namada_state::storage::Result; +use namada_state::{Epoch, StorageRead, StorageWrite}; +use namada_trans_token as token; + +use crate::types::{BondId, BondsAndUnbondsDetails, ResultSlashing, SlashType}; +use crate::{BecomeValidator, GenesisValidator, OwnedPosParams, PosParams}; + mod helpers; mod state_machine; mod state_machine_v2; @@ -6,3 +17,323 @@ mod test_pos; mod test_slash_and_redel; mod test_validator; mod utils; + +/// Gov impl type +pub type GovStore = namada_governance::Store; + +/// DI indirection +pub fn init_genesis_helper( + storage: &mut S, + params: &PosParams, + validators: impl Iterator, + current_epoch: namada_core::storage::Epoch, +) -> Result<()> +where + S: StorageRead + StorageWrite, +{ + crate::test_utils::init_genesis_helper::, token::Store<_>>( + storage, + params, + validators, + current_epoch, + ) +} + +/// DI indirection +pub fn test_init_genesis( + storage: &mut S, + owned: OwnedPosParams, + validators: impl Iterator + Clone, + current_epoch: namada_core::storage::Epoch, +) -> Result +where + S: StorageRead + StorageWrite, +{ + crate::test_utils::test_init_genesis::< + S, + namada_parameters::Store<_>, + GovStore<_>, + token::Store<_>, + >(storage, owned, validators, current_epoch) +} + +/// DI indirection +pub fn read_pos_params(storage: &S) -> Result +where + S: StorageRead, +{ + crate::storage::read_pos_params::>(storage) +} + +/// DI indirection +pub fn bond_tokens( + storage: &mut S, + source: Option<&Address>, + validator: &Address, + amount: token::Amount, + current_epoch: Epoch, + offset_opt: Option, +) -> Result<()> +where + S: StorageRead + StorageWrite, +{ + crate::bond_tokens::, token::Store<_>>( + storage, + source, + validator, + amount, + current_epoch, + offset_opt, + ) +} + +/// DI indirection +pub fn unbond_tokens( + storage: &mut S, + source: Option<&Address>, + validator: &Address, + amount: token::Amount, + current_epoch: Epoch, + is_redelegation: bool, +) -> Result +where + S: StorageRead + StorageWrite, +{ + crate::unbond_tokens::>( + storage, + source, + validator, + amount, + current_epoch, + is_redelegation, + ) +} + +/// DI indirection +pub fn bonds_and_unbonds( + storage: &S, + source: Option
, + validator: Option
, +) -> Result +where + S: StorageRead, +{ + crate::queries::bonds_and_unbonds::>( + storage, source, validator, + ) +} + +/// DI indirection +pub fn change_consensus_key( + storage: &mut S, + validator: &Address, + consensus_key: &common::PublicKey, + current_epoch: Epoch, +) -> Result<()> +where + S: StorageRead + StorageWrite, +{ + crate::change_consensus_key::>( + storage, + validator, + consensus_key, + current_epoch, + ) +} + +/// DI indirection +pub fn process_slashes( + storage: &mut S, + events: &mut impl EmitEvents, + current_epoch: Epoch, +) -> Result<()> +where + S: StorageRead + StorageWrite, +{ + crate::slashing::process_slashes::>( + storage, + events, + current_epoch, + ) +} + +/// DI indirection +pub fn unjail_validator( + storage: &mut S, + validator: &Address, + current_epoch: Epoch, +) -> Result<()> +where + S: StorageRead + StorageWrite, +{ + crate::unjail_validator::>(storage, validator, current_epoch) +} + +/// DI indirection +pub fn become_validator( + storage: &mut S, + args: BecomeValidator<'_>, +) -> Result<()> +where + S: StorageRead + StorageWrite, +{ + crate::become_validator::>(storage, args) +} + +/// DI indirection +pub fn withdraw_tokens( + storage: &mut S, + source: Option<&Address>, + validator: &Address, + current_epoch: Epoch, +) -> Result +where + S: StorageRead + StorageWrite, +{ + crate::withdraw_tokens::, token::Store<_>>( + storage, + source, + validator, + current_epoch, + ) +} + +/// DI indirection +pub fn redelegate_tokens( + storage: &mut S, + delegator: &Address, + src_validator: &Address, + dest_validator: &Address, + current_epoch: Epoch, + amount: token::Amount, +) -> Result<()> +where + S: StorageRead + StorageWrite, +{ + crate::redelegate_tokens::>( + storage, + delegator, + src_validator, + dest_validator, + current_epoch, + amount, + ) +} + +/// DI indirection +pub fn bond_amount( + storage: &S, + bond_id: &BondId, + epoch: Epoch, +) -> Result +where + S: StorageRead, +{ + crate::bond_amount::>(storage, bond_id, epoch) +} + +/// DI indirection +pub fn deactivate_validator( + storage: &mut S, + validator: &Address, + current_epoch: Epoch, +) -> Result<()> +where + S: StorageRead + StorageWrite, +{ + crate::deactivate_validator::>( + storage, + validator, + current_epoch, + ) +} + +/// DI indirection +pub fn reactivate_validator( + storage: &mut S, + validator: &Address, + current_epoch: Epoch, +) -> Result<()> +where + S: StorageRead + StorageWrite, +{ + crate::reactivate_validator::>( + storage, + validator, + current_epoch, + ) +} + +/// DI indirection +pub fn update_validator_deltas( + storage: &mut S, + params: &OwnedPosParams, + validator: &Address, + delta: token::Change, + current_epoch: namada_core::storage::Epoch, + offset_opt: Option, +) -> Result<()> +where + S: StorageRead + StorageWrite, +{ + crate::update_validator_deltas::>( + storage, + params, + validator, + delta, + current_epoch, + offset_opt, + ) +} + +/// DI indirection +pub fn read_below_threshold_validator_set_addresses( + storage: &S, + epoch: namada_core::storage::Epoch, +) -> Result> +where + S: StorageRead, +{ + crate::storage::read_below_threshold_validator_set_addresses::>( + storage, epoch, + ) +} + +/// DI indirection +#[allow(clippy::too_many_arguments)] +pub fn slash( + storage: &mut S, + params: &PosParams, + current_epoch: Epoch, + evidence_epoch: Epoch, + evidence_block_height: impl Into, + slash_type: SlashType, + validator: &Address, + validator_set_update_epoch: Epoch, +) -> Result<()> +where + S: StorageRead + StorageWrite, +{ + crate::slashing::slash::>( + storage, + params, + current_epoch, + evidence_epoch, + evidence_block_height, + slash_type, + validator, + validator_set_update_epoch, + ) +} + +/// DI indirection +pub fn find_delegations( + storage: &S, + owner: &Address, + epoch: &Epoch, +) -> Result> +where + S: StorageRead, +{ + crate::queries::find_delegations::>(storage, owner, epoch) +} diff --git a/crates/proof_of_stake/src/tests/state_machine.rs b/crates/proof_of_stake/src/tests/state_machine.rs index 82beb9ca155..bdccf109772 100644 --- a/crates/proof_of_stake/src/tests/state_machine.rs +++ b/crates/proof_of_stake/src/tests/state_machine.rs @@ -21,6 +21,7 @@ use namada_storage::collections::lazy_map::{ Collectable, NestedSubKey, SubKey, }; use namada_storage::StorageRead; +use namada_trans_token::{self as token, read_balance}; use proptest::prelude::*; use proptest::test_runner::Config; use proptest_state_machine::{ @@ -36,21 +37,25 @@ use crate::storage::{ enqueued_slashes_handle, read_all_validator_addresses, read_below_capacity_validator_set_addresses, read_below_capacity_validator_set_addresses_with_stake, - read_below_threshold_validator_set_addresses, read_consensus_validator_set_addresses_with_stake, }; use crate::tests::helpers::{advance_epoch, arb_params_and_genesis_validators}; -use crate::token::{self, read_balance}; +use crate::tests::{ + become_validator, bond_tokens, deactivate_validator, find_delegations, + process_slashes, reactivate_validator, + read_below_threshold_validator_set_addresses, read_pos_params, + redelegate_tokens, slash, unbond_tokens, unjail_validator, withdraw_tokens, +}; use crate::types::{ BondId, EagerRedelegatedBondsMap, GenesisValidator, ReverseOrdTokenAmount, Slash, SlashType, ValidatorState, WeightedValidator, }; use crate::{ below_capacity_validator_set_handle, consensus_validator_set_handle, - is_validator_frozen, read_pos_params, redelegate_tokens, - validator_deltas_handle, validator_slashes_handle, validator_state_handle, - BondsForRemovalRes, EagerRedelegatedUnbonds, FoldRedelegatedBondsResult, - ModifiedRedelegation, RedelegationError, ResultSlashing, + is_validator_frozen, validator_deltas_handle, validator_slashes_handle, + validator_state_handle, BondsForRemovalRes, EagerRedelegatedUnbonds, + FoldRedelegatedBondsResult, ModifiedRedelegation, RedelegationError, + ResultSlashing, }; prop_state_machine! { @@ -240,7 +245,7 @@ impl StateMachineTest for ConcretePosState { ); let mut s = TestState::default(); initial_state.gov_params.init_storage(&mut s).unwrap(); - crate::test_utils::test_init_genesis( + crate::tests::test_init_genesis( &mut s, initial_state.params.owned.clone(), initial_state.genesis_validators.clone().into_iter(), @@ -255,7 +260,7 @@ impl StateMachineTest for ConcretePosState { ref_state: &::State, transition: ::Transition, ) -> Self::SystemUnderTest { - let params = crate::read_pos_params(&state.s).unwrap(); + let params = read_pos_params(&state.s).unwrap(); let pos_balance = read_balance( &state.s, &state.s.in_mem().native_token, @@ -270,7 +275,7 @@ impl StateMachineTest for ConcretePosState { // Need to apply some slashing let current_epoch = state.s.in_mem().block.epoch; - crate::slashing::process_slashes( + process_slashes( &mut state.s, &mut namada_events::testing::VoidEventSink, current_epoch, @@ -292,7 +297,7 @@ impl StateMachineTest for ConcretePosState { tracing::debug!("\nCONCRETE Init validator"); let current_epoch = state.current_epoch(); - crate::become_validator( + become_validator( &mut state.s, crate::BecomeValidator { params: ¶ms, @@ -364,7 +369,7 @@ impl StateMachineTest for ConcretePosState { ); // Apply the bond - crate::bond_tokens( + bond_tokens( &mut state.s, Some(&id.source), &id.validator, @@ -431,7 +436,7 @@ impl StateMachineTest for ConcretePosState { .unwrap(); // Apply the unbond - crate::unbond_tokens( + unbond_tokens( &mut state.s, Some(&id.source), &id.validator, @@ -482,7 +487,7 @@ impl StateMachineTest for ConcretePosState { .unwrap(); // Apply the withdrawal - let withdrawn = crate::withdraw_tokens( + let withdrawn = withdraw_tokens( &mut state.s, Some(&source), &validator, @@ -575,10 +580,8 @@ impl StateMachineTest for ConcretePosState { .unwrap(); // Find delegations - let delegations_pre = crate::queries::find_delegations( - &state.s, &id.source, &pipeline, - ) - .unwrap(); + let delegations_pre = + find_delegations(&state.s, &id.source, &pipeline).unwrap(); // Apply redelegation let result = redelegate_tokens( @@ -697,10 +700,9 @@ impl StateMachineTest for ConcretePosState { // updated with redelegation. For the source reduced by the // redelegation amount and for the destination increased by // the redelegation amount, less any slashes. - let delegations_post = crate::queries::find_delegations( - &state.s, &id.source, &pipeline, - ) - .unwrap(); + let delegations_post = + find_delegations(&state.s, &id.source, &pipeline) + .unwrap(); let src_delegation_pre = delegations_pre .get(&id.validator) .cloned() @@ -736,7 +738,7 @@ impl StateMachineTest for ConcretePosState { tracing::debug!("\nCONCRETE Misbehavior"); let current_epoch = state.current_epoch(); // Record the slash evidence - crate::slashing::slash( + slash( &mut state.s, ¶ms, current_epoch, @@ -766,7 +768,7 @@ impl StateMachineTest for ConcretePosState { let current_epoch = state.current_epoch(); // Unjail the validator - crate::unjail_validator(&mut state.s, &address, current_epoch) + unjail_validator(&mut state.s, &address, current_epoch) .unwrap(); // Post-conditions @@ -778,12 +780,8 @@ impl StateMachineTest for ConcretePosState { let current_epoch = state.current_epoch(); // Deactivate the validator - crate::deactivate_validator( - &mut state.s, - &address, - current_epoch, - ) - .unwrap(); + deactivate_validator(&mut state.s, &address, current_epoch) + .unwrap(); // Post-conditions let params = read_pos_params(&state.s).unwrap(); @@ -796,12 +794,8 @@ impl StateMachineTest for ConcretePosState { let current_epoch = state.current_epoch(); // Reactivate the validator - crate::reactivate_validator( - &mut state.s, - &address, - current_epoch, - ) - .unwrap(); + reactivate_validator(&mut state.s, &address, current_epoch) + .unwrap(); // Post-conditions let params = read_pos_params(&state.s).unwrap(); diff --git a/crates/proof_of_stake/src/tests/state_machine_v2.rs b/crates/proof_of_stake/src/tests/state_machine_v2.rs index 4b8fb024e2a..a7eac77ab5c 100644 --- a/crates/proof_of_stake/src/tests/state_machine_v2.rs +++ b/crates/proof_of_stake/src/tests/state_machine_v2.rs @@ -20,6 +20,7 @@ use namada_governance::parameters::GovernanceParameters; use namada_state::testing::TestState; use namada_storage::collections::lazy_map::{NestedSubKey, SubKey}; use namada_storage::StorageRead; +use namada_trans_token::{self as token, read_balance}; use proptest::prelude::*; use proptest::test_runner::Config; use proptest_state_machine::{ @@ -34,18 +35,21 @@ use super::helpers::advance_epoch; use super::utils::DbgPrintDiff; use crate::parameters::testing::arb_rate; use crate::parameters::PosParams; -use crate::queries::find_delegations; use crate::slashing::find_slashes_in_range; use crate::storage::{ enqueued_slashes_handle, read_all_validator_addresses, read_below_capacity_validator_set_addresses, read_below_capacity_validator_set_addresses_with_stake, - read_below_threshold_validator_set_addresses, read_consensus_validator_set_addresses_with_stake, }; use crate::tests::helpers::arb_params_and_genesis_validators; use crate::tests::utils::pause_for_enter; -use crate::token::read_balance; +use crate::tests::{ + become_validator, bond_tokens, find_delegations, process_slashes, + read_below_threshold_validator_set_addresses, read_pos_params, + redelegate_tokens, slash, unbond_tokens, unjail_validator, withdraw_tokens, + GovStore, +}; use crate::types::{ BondId, GenesisValidator, ReverseOrdTokenAmount, Slash, SlashType, ValidatorState, WeightedValidator, @@ -53,8 +57,8 @@ use crate::types::{ use crate::{ below_capacity_validator_set_handle, bond_handle, consensus_validator_set_handle, delegator_redelegated_bonds_handle, - read_pos_params, redelegate_tokens, token, validator_deltas_handle, - validator_slashes_handle, validator_state_handle, RedelegationError, + validator_deltas_handle, validator_slashes_handle, validator_state_handle, + RedelegationError, }; prop_state_machine! { @@ -1947,7 +1951,7 @@ impl StateMachineTest for ConcretePosState { ); let mut s = TestState::default(); initial_state.gov_params.init_storage(&mut s).unwrap(); - crate::test_utils::init_genesis_helper( + crate::tests::init_genesis_helper( &mut s, &initial_state.params, initial_state.genesis_validators.clone().into_iter(), @@ -1978,7 +1982,7 @@ impl StateMachineTest for ConcretePosState { pause_for_enter(); - let params = crate::read_pos_params(&state.s).unwrap(); + let params = read_pos_params(&state.s).unwrap(); let pos_balance = read_balance( &state.s, &state.s.in_mem().native_token, @@ -1993,7 +1997,7 @@ impl StateMachineTest for ConcretePosState { // Need to apply some slashing let current_epoch = state.s.in_mem().block.epoch; - crate::slashing::process_slashes( + process_slashes( &mut state.s, &mut namada_events::testing::VoidEventSink, current_epoch, @@ -2015,7 +2019,7 @@ impl StateMachineTest for ConcretePosState { tracing::debug!("\nCONCRETE Init validator"); let current_epoch = state.current_epoch(); - crate::become_validator( + become_validator( &mut state.s, crate::BecomeValidator { params: ¶ms, @@ -2087,7 +2091,7 @@ impl StateMachineTest for ConcretePosState { ); // Apply the bond - crate::bond_tokens( + bond_tokens( &mut state.s, Some(&id.source), &id.validator, @@ -2152,7 +2156,7 @@ impl StateMachineTest for ConcretePosState { .unwrap(); // Apply the unbond - crate::unbond_tokens( + unbond_tokens( &mut state.s, Some(&id.source), &id.validator, @@ -2228,7 +2232,7 @@ impl StateMachineTest for ConcretePosState { // .unwrap(); // Apply the withdrawal - let withdrawn = crate::withdraw_tokens( + let withdrawn = withdraw_tokens( &mut state.s, Some(&source), &validator, @@ -2684,7 +2688,7 @@ impl StateMachineTest for ConcretePosState { tracing::debug!("\nCONCRETE Misbehavior"); let current_epoch = state.current_epoch(); // Record the slash evidence - crate::slashing::slash( + slash( &mut state.s, ¶ms, current_epoch, @@ -2714,7 +2718,7 @@ impl StateMachineTest for ConcretePosState { let current_epoch = state.current_epoch(); // Unjail the validator - crate::unjail_validator(&mut state.s, &address, current_epoch) + unjail_validator(&mut state.s, &address, current_epoch) .unwrap(); // Post-conditions @@ -3551,7 +3555,10 @@ impl ConcretePosState { let max_slash_round_err = records.slash_round_err_tolerance(epoch); let conc_bond_amount = - crate::bond_amount(&self.s, &bond_id, epoch).unwrap(); + crate::bond_amount::<_, GovStore<_>>( + &self.s, &bond_id, epoch, + ) + .unwrap(); let ref_bond_amount = records.amount(epoch); assert!( ref_bond_amount diff --git a/crates/proof_of_stake/src/tests/test_helper_fns.rs b/crates/proof_of_stake/src/tests/test_helper_fns.rs index 9d0d443f4a8..830febed1c5 100644 --- a/crates/proof_of_stake/src/tests/test_helper_fns.rs +++ b/crates/proof_of_stake/src/tests/test_helper_fns.rs @@ -24,6 +24,7 @@ use crate::storage::{ validator_slashes_handle, validator_total_redelegated_bonded_handle, validator_total_redelegated_unbonded_handle, write_pos_params, }; +use crate::tests::GovStore; use crate::types::{ EagerRedelegatedBondsMap, RedelegatedTokens, Slash, SlashType, }; @@ -50,13 +51,13 @@ fn test_find_bonds_to_remove() { let (e1, e2, e6) = (Epoch(1), Epoch(2), Epoch(6)); bond_handle - .set(&mut storage, token::Amount::from(5), e1, 0) + .set::<_, GovStore<_>>(&mut storage, token::Amount::from(5), e1, 0) .unwrap(); bond_handle - .set(&mut storage, token::Amount::from(3), e2, 0) + .set::<_, GovStore<_>>(&mut storage, token::Amount::from(3), e2, 0) .unwrap(); bond_handle - .set(&mut storage, token::Amount::from(8), e6, 0) + .set::<_, GovStore<_>>(&mut storage, token::Amount::from(8), e6, 0) .unwrap(); // Test 1 @@ -1330,7 +1331,7 @@ fn test_slash_validator() { // Test case 1 total_bonded - .set(&mut storage, 23.into(), infraction_epoch - 2, 0) + .set::<_, GovStore<_>>(&mut storage, 23.into(), infraction_epoch - 2, 0) .unwrap(); let res = slash_validator( &storage, @@ -1345,7 +1346,7 @@ fn test_slash_validator() { // Test case 2 total_bonded - .set(&mut storage, 17.into(), infraction_epoch - 2, 0) + .set::<_, GovStore<_>>(&mut storage, 17.into(), infraction_epoch - 2, 0) .unwrap(); total_unbonded .at(&(current_epoch + params.pipeline_len)) @@ -1421,7 +1422,7 @@ fn test_slash_validator() { // Test case 5 total_bonded_handle(&bob) - .set(&mut storage, 19.into(), infraction_epoch - 2, 0) + .set::<_, GovStore<_>>(&mut storage, 19.into(), infraction_epoch - 2, 0) .unwrap(); total_unbonded_handle(&bob) .at(&(current_epoch + params.pipeline_len)) @@ -1468,10 +1469,10 @@ fn test_slash_validator() { .remove_all(&mut storage, ¤t_epoch) .unwrap(); total_bonded_handle(&bob) - .set(&mut storage, 23.into(), infraction_epoch - 2, 0) + .set::<_, GovStore<_>>(&mut storage, 23.into(), infraction_epoch - 2, 0) .unwrap(); total_bonded_handle(&bob) - .set(&mut storage, 6.into(), current_epoch, 0) + .set::<_, GovStore<_>>(&mut storage, 6.into(), current_epoch, 0) .unwrap(); let res = slash_validator( @@ -1531,7 +1532,7 @@ fn test_slash_validator() { .remove_all(&mut storage, ¤t_epoch.next()) .unwrap(); total_bonded - .set(&mut storage, 6.into(), current_epoch, 0) + .set::<_, GovStore<_>>(&mut storage, 6.into(), current_epoch, 0) .unwrap(); total_redelegated_bonded .at(¤t_epoch) @@ -1587,7 +1588,7 @@ fn test_slash_validator() { // Test case 11 total_bonded - .set(&mut storage, 2.into(), current_epoch, 0) + .set::<_, GovStore<_>>(&mut storage, 2.into(), current_epoch, 0) .unwrap(); total_redelegated_unbonded .at(¤t_epoch.next()) @@ -1624,10 +1625,10 @@ fn test_slash_validator() { // Test case 12 total_bonded - .set(&mut storage, 6.into(), current_epoch, 0) + .set::<_, GovStore<_>>(&mut storage, 6.into(), current_epoch, 0) .unwrap(); total_bonded - .set(&mut storage, 2.into(), current_epoch.next(), 0) + .set::<_, GovStore<_>>(&mut storage, 2.into(), current_epoch.next(), 0) .unwrap(); total_redelegated_bonded .remove_all(&mut storage, ¤t_epoch) @@ -1971,7 +1972,7 @@ fn test_from_sm_case_1() { // Insert the data - bonds and redelegated bonds let bonds_handle = bond_handle(&owner, &validator); bonds_handle - .add( + .add::<_, GovStore<_>>( &mut storage, epoch_1_redeleg_1 + epoch_1_redeleg_2, outer_epoch_1, @@ -1979,7 +1980,12 @@ fn test_from_sm_case_1() { ) .unwrap(); bonds_handle - .add(&mut storage, epoch_2_redeleg_2, outer_epoch_2, 0) + .add::<_, GovStore<_>>( + &mut storage, + epoch_2_redeleg_2, + outer_epoch_2, + 0, + ) .unwrap(); let redelegated_bonds_map_1 = delegator_redelegated_bonds_handle(&owner) diff --git a/crates/proof_of_stake/src/tests/test_pos.rs b/crates/proof_of_stake/src/tests/test_pos.rs index 8d853e60866..d8829250e7b 100644 --- a/crates/proof_of_stake/src/tests/test_pos.rs +++ b/crates/proof_of_stake/src/tests/test_pos.rs @@ -15,50 +15,53 @@ use namada_core::{address, key}; use namada_state::testing::TestState; use namada_storage::collections::lazy_map::Collectable; use namada_storage::StorageRead; +use namada_trans_token::{ + self as token, credit_tokens, get_effective_total_native_supply, + read_balance, +}; use proptest::prelude::*; use proptest::test_runner::Config; // Use `RUST_LOG=info` (or another tracing level) and `--nocapture` to see // `tracing` logs from tests use test_log::test; -use token::get_effective_total_native_supply; use crate::epoched::EpochOffset; use crate::parameters::testing::arb_pos_params; use crate::parameters::OwnedPosParams; -use crate::queries::{ - bonds_and_unbonds, find_delegation_validators, find_delegations, -}; +use crate::queries::find_delegation_validators; use crate::rewards::{ log_block_rewards_aux, update_rewards_products_and_mint_inflation, PosRewardsCalculator, }; -use crate::slashing::{process_slashes, slash}; use crate::storage::{ delegation_targets_handle, get_consensus_key_set, liveness_sum_missed_votes_handle, - read_below_threshold_validator_set_addresses, read_consensus_validator_set_addresses_with_stake, read_total_stake, read_validator_deltas_value, rewards_accumulator_handle, total_deltas_handle, }; -use crate::test_utils::test_init_genesis; use crate::tests::helpers::{ advance_epoch, arb_genesis_validators, arb_params_and_genesis_validators, get_genesis_validators, }; -use crate::token::{credit_tokens, read_balance}; +use crate::tests::{ + bond_amount, bond_tokens, bonds_and_unbonds, change_consensus_key, + find_delegations, process_slashes, + read_below_threshold_validator_set_addresses, redelegate_tokens, slash, + test_init_genesis, unbond_tokens, unjail_validator, withdraw_tokens, + GovStore, +}; use crate::types::{ into_tm_voting_power, BondDetails, BondId, BondsAndUnbondsDetails, GenesisValidator, SlashType, UnbondDetails, ValidatorState, VoteInfo, WeightedValidator, }; use crate::{ - below_capacity_validator_set_handle, bond_handle, bond_tokens, - change_consensus_key, consensus_validator_set_handle, is_delegator, - is_validator, jail_for_liveness, read_validator_stake, redelegate_tokens, - staking_token_address, token, unbond_handle, unbond_tokens, - unjail_validator, validator_consensus_key_handle, - validator_set_positions_handle, validator_state_handle, withdraw_tokens, + below_capacity_validator_set_handle, bond_handle, + consensus_validator_set_handle, is_delegator, is_validator, + jail_for_liveness, read_validator_stake, staking_token_address, + unbond_handle, validator_consensus_key_handle, + validator_set_positions_handle, validator_state_handle, }; proptest! { @@ -1157,7 +1160,7 @@ fn test_unslashed_bond_amount_aux(validators: Vec) { Epoch(0), current_epoch + params.pipeline_len, ) { - let bond_amount = crate::bond_amount( + let amount = bond_amount( &storage, &BondId { source: delegator.clone(), @@ -1170,8 +1173,8 @@ fn test_unslashed_bond_amount_aux(validators: Vec) { let val_stake = crate::read_validator_stake(&storage, ¶ms, &validator1, epoch) .unwrap(); - // dbg!(&bond_amount); - assert_eq!(val_stake - val1_init_stake, bond_amount); + // dbg!(&amount); + assert_eq!(val_stake - val1_init_stake, amount); } } @@ -1264,7 +1267,7 @@ fn test_log_block_rewards_aux_aux( }; let (votes, signing_stake, non_voters) = prep_votes(current_epoch); - log_block_rewards_aux( + log_block_rewards_aux::<_, GovStore<_>>( &mut s, current_epoch, &proposer_address, @@ -1457,7 +1460,7 @@ fn test_update_rewards_products_aux(validators: Vec) { // Distribute inflation into rewards let last_epoch = current_epoch.prev().unwrap(); let inflation = token::Amount::native_whole(10_000_000); - update_rewards_products_and_mint_inflation( + update_rewards_products_and_mint_inflation::<_, token::Store<_>>( &mut s, ¶ms, last_epoch, @@ -1778,7 +1781,13 @@ fn test_jail_for_liveness_aux(validators: Vec) { .unwrap(); } - jail_for_liveness(s, ¶ms, current_epoch, jail_epoch).unwrap(); + jail_for_liveness::<_, GovStore<_>>( + s, + ¶ms, + current_epoch, + jail_epoch, + ) + .unwrap(); for GenesisValidator { address, .. } in &validators_who_missed_votes { let state_jail_epoch = validator_state_handle(address) diff --git a/crates/proof_of_stake/src/tests/test_slash_and_redel.rs b/crates/proof_of_stake/src/tests/test_slash_and_redel.rs index 4f04e90945d..c374408a72d 100644 --- a/crates/proof_of_stake/src/tests/test_slash_and_redel.rs +++ b/crates/proof_of_stake/src/tests/test_slash_and_redel.rs @@ -17,14 +17,13 @@ use namada_core::token::NATIVE_MAX_DECIMAL_PLACES; use namada_state::testing::TestState; use namada_storage::collections::lazy_map::Collectable; use namada_storage::StorageRead; +use namada_trans_token::{self as token, credit_tokens, read_balance}; use proptest::prelude::*; use proptest::test_runner::Config; // Use `RUST_LOG=info` (or another tracing level) and `--nocapture` to see // `tracing` logs from tests use test_log::test; -use crate::queries::bonds_and_unbonds; -use crate::slashing::{process_slashes, slash}; use crate::storage::{ bond_handle, delegator_redelegated_bonds_handle, delegator_redelegated_unbonds_handle, enqueued_slashes_handle, @@ -35,17 +34,17 @@ use crate::storage::{ validator_total_redelegated_bonded_handle, validator_total_redelegated_unbonded_handle, }; -use crate::test_utils::test_init_genesis; use crate::tests::helpers::{ advance_epoch, arb_genesis_validators, arb_redelegation_amounts, test_slashes_with_unbonding_params, }; -use crate::token::{credit_tokens, read_balance}; -use crate::types::{BondId, GenesisValidator, Slash, SlashType}; -use crate::{ - bond_tokens, redelegate_tokens, staking_token_address, token, - unbond_tokens, withdraw_tokens, OwnedPosParams, RedelegationError, +use crate::tests::{ + bond_amount, bond_tokens, bonds_and_unbonds, process_slashes, + redelegate_tokens, slash, test_init_genesis, unbond_tokens, + withdraw_tokens, }; +use crate::types::{BondId, GenesisValidator, Slash, SlashType}; +use crate::{staking_token_address, OwnedPosParams, RedelegationError}; proptest! { // Generate arb valid input for `test_simple_redelegation_aux` @@ -1320,10 +1319,9 @@ fn test_overslashing_aux(mut validators: Vec) { source: validator.clone(), validator: validator.clone(), }; - let bond_amount = - crate::bond_amount(&storage, &self_bond_id, epoch).unwrap(); + let amount = bond_amount(&storage, &self_bond_id, epoch).unwrap(); let exp_bond_amount = offending_stake - exp_slashed_1; - assert_eq!(bond_amount, exp_bond_amount); + assert_eq!(amount, exp_bond_amount); // Advance to processing epoch 2 loop { @@ -1367,12 +1365,11 @@ fn test_overslashing_aux(mut validators: Vec) { validator: validator.clone(), }; let delegation_amount = - crate::bond_amount(&storage, &delegation_id, epoch).unwrap(); + bond_amount(&storage, &delegation_id, epoch).unwrap(); let exp_del_amount = amount_del - exp_slashed_from_delegation; assert_eq!(delegation_amount, exp_del_amount); - let self_bond_amount = - crate::bond_amount(&storage, &self_bond_id, epoch).unwrap(); + let self_bond_amount = bond_amount(&storage, &self_bond_id, epoch).unwrap(); let exp_bond_amount = token::Amount::zero(); assert_eq!(self_bond_amount, exp_bond_amount); } @@ -1640,7 +1637,7 @@ fn test_slashed_bond_amount_aux(validators: Vec) { let pipeline_epoch = current_epoch + params.pipeline_len; - let del_bond_amount = crate::bond_amount( + let del_bond_amount = bond_amount( &storage, &BondId { source: delegator.clone(), @@ -1650,7 +1647,7 @@ fn test_slashed_bond_amount_aux(validators: Vec) { ) .unwrap_or_default(); - let self_bond_amount = crate::bond_amount( + let self_bond_amount = bond_amount( &storage, &BondId { source: validator1.clone(), @@ -1660,13 +1657,9 @@ fn test_slashed_bond_amount_aux(validators: Vec) { ) .unwrap_or_default(); - let val_stake = crate::read_validator_stake( - &storage, - ¶ms, - &validator1, - pipeline_epoch, - ) - .unwrap(); + let val_stake = + read_validator_stake(&storage, ¶ms, &validator1, pipeline_epoch) + .unwrap(); let diff = val_stake - self_bond_amount - del_bond_amount; assert!(diff <= 2.into()); @@ -1762,7 +1755,7 @@ fn test_one_slash_per_block_height() { let processing_epoch = current_epoch + params.slash_processing_epoch_offset(); let enqueue = |stg: &mut TestState, slash: &Slash, validator: &Address| { - crate::slashing::slash( + crate::tests::slash( stg, ¶ms, current_epoch, diff --git a/crates/proof_of_stake/src/tests/test_validator.rs b/crates/proof_of_stake/src/tests/test_validator.rs index b17750cd4bc..73287eb0e18 100644 --- a/crates/proof_of_stake/src/tests/test_validator.rs +++ b/crates/proof_of_stake/src/tests/test_validator.rs @@ -13,6 +13,7 @@ use namada_core::storage::Epoch; use namada_core::token; use namada_state::testing::TestState; use namada_storage::collections::lazy_map; +use namada_trans_token::credit_tokens; use proptest::prelude::*; use proptest::test_runner::Config; // Use `RUST_LOG=info` (or another tracing level) and `--nocapture` to see @@ -25,17 +26,19 @@ use crate::storage::{ consensus_validator_set_handle, find_validator_by_raw_hash, get_num_consensus_validators, read_below_capacity_validator_set_addresses_with_stake, - read_below_threshold_validator_set_addresses, - read_consensus_validator_set_addresses_with_stake, update_validator_deltas, + read_consensus_validator_set_addresses_with_stake, validator_addresses_handle, validator_consensus_key_handle, validator_set_positions_handle, write_validator_address_raw_hash, }; -use crate::test_utils::{init_genesis_helper, test_init_genesis}; use crate::tests::helpers::{ advance_epoch, arb_genesis_validators, arb_params_and_genesis_validators, get_tendermint_set_updates, }; -use crate::token::credit_tokens; +use crate::tests::{ + become_validator, bond_tokens, change_consensus_key, init_genesis_helper, + read_below_threshold_validator_set_addresses, test_init_genesis, + unbond_tokens, update_validator_deltas, withdraw_tokens, GovStore, +}; use crate::types::{ into_tm_voting_power, ConsensusValidator, GenesisValidator, Position, ReverseOrdTokenAmount, ValidatorSetUpdate, WeightedValidator, @@ -44,9 +47,7 @@ use crate::validator_set_update::{ insert_validator_into_validator_set, update_validator_set, }; use crate::{ - become_validator, bond_tokens, change_consensus_key, is_validator, - staking_token_address, unbond_tokens, withdraw_tokens, BecomeValidator, - OwnedPosParams, + is_validator, staking_token_address, BecomeValidator, OwnedPosParams, }; proptest! { @@ -395,7 +396,7 @@ fn test_validator_sets() { pk: &common::PublicKey, stake: token::Amount, epoch: Epoch| { - insert_validator_into_validator_set( + insert_validator_into_validator_set::<_, GovStore<_>>( s, ¶ms, addr, @@ -411,7 +412,7 @@ fn test_validator_sets() { // Set their consensus key (needed for // `validator_set_update_tendermint` fn) validator_consensus_key_handle(addr) - .set(s, pk.clone(), epoch, params.pipeline_len) + .set::<_, GovStore<_>>(s, pk.clone(), epoch, params.pipeline_len) .unwrap(); }; @@ -634,8 +635,15 @@ fn test_validator_sets() { // Because `update_validator_set` and `update_validator_deltas` are // effective from pipeline offset, we use pipeline epoch for the rest of the // checks - update_validator_set(&mut s, ¶ms, &val1, -unbond.change(), epoch, None) - .unwrap(); + update_validator_set::<_, GovStore<_>>( + &mut s, + ¶ms, + &val1, + -unbond.change(), + epoch, + None, + ) + .unwrap(); update_validator_deltas( &mut s, ¶ms, @@ -833,8 +841,15 @@ fn test_validator_sets() { let bond = token::Amount::from_uint(500_000, 0).unwrap(); let stake6 = stake6 + bond; - update_validator_set(&mut s, ¶ms, &val6, bond.change(), epoch, None) - .unwrap(); + update_validator_set::<_, GovStore<_>>( + &mut s, + ¶ms, + &val6, + bond.change(), + epoch, + None, + ) + .unwrap(); update_validator_deltas(&mut s, ¶ms, &val6, bond.change(), epoch, None) .unwrap(); let val6_bond_epoch = pipeline_epoch; @@ -1073,7 +1088,7 @@ fn test_validator_sets_swap() { pk: &common::PublicKey, stake: token::Amount, epoch: Epoch| { - insert_validator_into_validator_set( + insert_validator_into_validator_set::<_, GovStore<_>>( s, ¶ms, addr, @@ -1089,7 +1104,7 @@ fn test_validator_sets_swap() { // Set their consensus key (needed for // `validator_set_update_tendermint` fn) validator_consensus_key_handle(addr) - .set(s, pk.clone(), epoch, params.pipeline_len) + .set::<_, GovStore<_>>(s, pk.clone(), epoch, params.pipeline_len) .unwrap(); }; @@ -1113,8 +1128,15 @@ fn test_validator_sets_swap() { assert_eq!(into_tm_voting_power(params.tm_votes_per_token, stake2), 0); assert_eq!(into_tm_voting_power(params.tm_votes_per_token, stake3), 0); - update_validator_set(&mut s, ¶ms, &val2, bond2.change(), epoch, None) - .unwrap(); + update_validator_set::<_, GovStore<_>>( + &mut s, + ¶ms, + &val2, + bond2.change(), + epoch, + None, + ) + .unwrap(); update_validator_deltas( &mut s, ¶ms, @@ -1125,8 +1147,15 @@ fn test_validator_sets_swap() { ) .unwrap(); - update_validator_set(&mut s, ¶ms, &val3, bond3.change(), epoch, None) - .unwrap(); + update_validator_set::<_, GovStore<_>>( + &mut s, + ¶ms, + &val3, + bond3.change(), + epoch, + None, + ) + .unwrap(); update_validator_deltas( &mut s, ¶ms, @@ -1152,8 +1181,15 @@ fn test_validator_sets_swap() { into_tm_voting_power(params.tm_votes_per_token, stake3) ); - update_validator_set(&mut s, ¶ms, &val2, bonds.change(), epoch, None) - .unwrap(); + update_validator_set::<_, GovStore<_>>( + &mut s, + ¶ms, + &val2, + bonds.change(), + epoch, + None, + ) + .unwrap(); update_validator_deltas( &mut s, ¶ms, @@ -1164,8 +1200,15 @@ fn test_validator_sets_swap() { ) .unwrap(); - update_validator_set(&mut s, ¶ms, &val3, bonds.change(), epoch, None) - .unwrap(); + update_validator_set::<_, GovStore<_>>( + &mut s, + ¶ms, + &val3, + bonds.change(), + epoch, + None, + ) + .unwrap(); update_validator_deltas( &mut s, ¶ms, @@ -1215,8 +1258,15 @@ fn test_validator_sets_swap() { let bonds = token::Amount::native_whole(1); let stake2 = stake2 + bonds; - update_validator_set(&mut s, ¶ms, &val2, bonds.change(), epoch, None) - .unwrap(); + update_validator_set::<_, GovStore<_>>( + &mut s, + ¶ms, + &val2, + bonds.change(), + epoch, + None, + ) + .unwrap(); update_validator_deltas( &mut s, ¶ms, @@ -1293,7 +1343,8 @@ fn test_purge_validator_information_aux(validators: Vec) { }; gov_params.init_storage(&mut s).unwrap(); - let params = crate::read_non_pos_owned_params(&s, owned).unwrap(); + let params = + crate::read_non_pos_owned_params::<_, GovStore<_>>(&s, owned).unwrap(); init_genesis_helper(&mut s, ¶ms, validators.into_iter(), current_epoch) .unwrap(); diff --git a/crates/proof_of_stake/src/validator_set_update.rs b/crates/proof_of_stake/src/validator_set_update.rs index 5b2d2dba45c..d46b89b3cb0 100644 --- a/crates/proof_of_stake/src/validator_set_update.rs +++ b/crates/proof_of_stake/src/validator_set_update.rs @@ -8,6 +8,7 @@ use namada_core::storage::Epoch; use namada_core::token; use namada_storage::collections::lazy_map::{NestedSubKey, SubKey}; use namada_storage::{StorageRead, StorageWrite}; +use namada_systems::governance; use once_cell::unsync::Lazy; use crate::storage::{ @@ -25,7 +26,7 @@ use crate::PosParams; /// Update validator set at the pipeline epoch when a validator receives a new /// bond and when its bond is unbonded (self-bond or delegation). -pub fn update_validator_set( +pub fn update_validator_set( storage: &mut S, params: &PosParams, validator: &Address, @@ -35,6 +36,7 @@ pub fn update_validator_set( ) -> namada_storage::Result<()> where S: StorageRead + StorageWrite, + Gov: governance::Read, { if token_change.is_zero() { return Ok(()); @@ -99,7 +101,7 @@ where "Demoting this validator to the below-threshold set" ); // Set the validator state as below-threshold - validator_state_handle(validator).set( + validator_state_handle(validator).set::( storage, ValidatorState::BelowThreshold, current_epoch, @@ -136,12 +138,13 @@ where &epoch, &removed_max_below_capacity, )?; - validator_state_handle(&removed_max_below_capacity).set( - storage, - ValidatorState::Consensus, - current_epoch, - offset, - )?; + validator_state_handle(&removed_max_below_capacity) + .set::( + storage, + ValidatorState::Consensus, + current_epoch, + offset, + )?; } } else if tokens_post < max_below_capacity_validator_amount { tracing::debug!( @@ -171,12 +174,13 @@ where &epoch, &removed_max_below_capacity, )?; - validator_state_handle(&removed_max_below_capacity).set( - storage, - ValidatorState::Consensus, - current_epoch, - offset, - )?; + validator_state_handle(&removed_max_below_capacity) + .set::( + storage, + ValidatorState::Consensus, + current_epoch, + offset, + )?; // Insert the current validator into the below-capacity set insert_validator_into_set( @@ -185,7 +189,7 @@ where &epoch, validator, )?; - validator_state_handle(validator).set( + validator_state_handle(validator).set::( storage, ValidatorState::BelowCapacity, current_epoch, @@ -227,7 +231,7 @@ where a consensus validator to the below-capacity set" ); - insert_into_consensus_and_demote_to_below_cap( + insert_into_consensus_and_demote_to_below_cap::( storage, validator, tokens_post, @@ -246,7 +250,7 @@ where &epoch, validator, )?; - validator_state_handle(validator).set( + validator_state_handle(validator).set::( storage, ValidatorState::BelowCapacity, current_epoch, @@ -258,7 +262,7 @@ where "Demoting this validator to the below-threshold set" ); - validator_state_handle(validator).set( + validator_state_handle(validator).set::( storage, ValidatorState::BelowThreshold, current_epoch, @@ -293,7 +297,7 @@ where &epoch, validator, )?; - validator_state_handle(validator).set( + validator_state_handle(validator).set::( storage, ValidatorState::Consensus, current_epoch, @@ -313,7 +317,7 @@ where a consensus validator to the below-capacity set" ); - insert_into_consensus_and_demote_to_below_cap( + insert_into_consensus_and_demote_to_below_cap::( storage, validator, tokens_post, @@ -335,7 +339,7 @@ where &epoch, validator, )?; - validator_state_handle(validator).set( + validator_state_handle(validator).set::( storage, ValidatorState::BelowCapacity, current_epoch, @@ -350,7 +354,7 @@ where /// Insert the new validator into the right validator set (depending on its /// stake) -pub fn insert_validator_into_validator_set( +pub fn insert_validator_into_validator_set( storage: &mut S, params: &PosParams, address: &Address, @@ -360,6 +364,7 @@ pub fn insert_validator_into_validator_set( ) -> namada_storage::Result<()> where S: StorageRead + StorageWrite, + Gov: governance::Read, { let target_epoch = checked!(current_epoch + offset)?; let consensus_set = consensus_validator_set_handle().at(&target_epoch); @@ -369,7 +374,7 @@ where get_num_consensus_validators(storage, target_epoch)?; if stake < params.validator_stake_threshold { - validator_state_handle(address).set( + validator_state_handle(address).set::( storage, ValidatorState::BelowThreshold, current_epoch, @@ -382,7 +387,7 @@ where &target_epoch, address, )?; - validator_state_handle(address).set( + validator_state_handle(address).set::( storage, ValidatorState::Consensus, current_epoch, @@ -414,7 +419,7 @@ where &target_epoch, &removed, )?; - validator_state_handle(&removed).set( + validator_state_handle(&removed).set::( storage, ValidatorState::BelowCapacity, current_epoch, @@ -428,7 +433,7 @@ where address, )?; // Update and set the validator states - validator_state_handle(address).set( + validator_state_handle(address).set::( storage, ValidatorState::Consensus, current_epoch, @@ -442,7 +447,7 @@ where &target_epoch, address, )?; - validator_state_handle(address).set( + validator_state_handle(address).set::( storage, ValidatorState::BelowCapacity, current_epoch, @@ -515,13 +520,14 @@ where /// determined as the validator in the below-capacity set with the largest stake /// and the lowest `Position`. Assumes that there is adequate space within the /// consensus set already. -pub fn promote_next_below_capacity_validator_to_consensus( +pub fn promote_next_below_capacity_validator_to_consensus( storage: &mut S, current_epoch: Epoch, offset: u64, ) -> namada_storage::Result<()> where S: StorageRead + StorageWrite, + Gov: governance::Read, { let epoch = checked!(current_epoch + offset)?; let below_cap_set = below_capacity_validator_set_handle().at(&epoch); @@ -545,7 +551,7 @@ where &epoch, &promoted_validator, )?; - validator_state_handle(&promoted_validator).set( + validator_state_handle(&promoted_validator).set::( storage, ValidatorState::Consensus, current_epoch, @@ -876,7 +882,7 @@ where } #[allow(clippy::too_many_arguments)] -fn insert_into_consensus_and_demote_to_below_cap( +fn insert_into_consensus_and_demote_to_below_cap( storage: &mut S, validator: &Address, tokens_post: token::Amount, @@ -888,6 +894,7 @@ fn insert_into_consensus_and_demote_to_below_cap( ) -> namada_storage::Result<()> where S: StorageRead + StorageWrite, + Gov: governance::Read, { // First, remove the last position min consensus validator let consensus_vals_min = consensus_set.at(&min_consensus_amount); @@ -908,7 +915,7 @@ where &offset_epoch, &removed_min_consensus, )?; - validator_state_handle(&removed_min_consensus).set( + validator_state_handle(&removed_min_consensus).set::( storage, ValidatorState::BelowCapacity, current_epoch, @@ -922,7 +929,7 @@ where &offset_epoch, validator, )?; - validator_state_handle(validator).set( + validator_state_handle(validator).set::( storage, ValidatorState::Consensus, current_epoch, diff --git a/crates/proof_of_stake/src/vp.rs b/crates/proof_of_stake/src/vp.rs index 869f733e18d..6699f702a0e 100644 --- a/crates/proof_of_stake/src/vp.rs +++ b/crates/proof_of_stake/src/vp.rs @@ -17,7 +17,7 @@ use namada_vp::native_vp::{ }; use thiserror::Error; -use crate::storage::read_pos_params; +use crate::storage::read_owned_pos_params; use crate::storage_key::is_params_key; use crate::types::BondId; use crate::{storage_key, token}; @@ -40,7 +40,6 @@ pub type Result = std::result::Result; pub struct PosVp<'ctx, S, CA, EVAL, Gov> where S: StateRead, - EVAL: VpEvaluator<'ctx, S, CA, EVAL>, { /// Context to interact with the host structures. pub ctx: Ctx<'ctx, S, CA, EVAL>, @@ -314,7 +313,7 @@ where } } -impl<'ctx, S, CA, EVAL, Gov> PosVp<'ctx, S, CA, EVAL, Gov> +impl<'view, 'ctx: 'view, S, CA, EVAL, Gov> PosVp<'ctx, S, CA, EVAL, Gov> where S: StateRead, CA: 'static + Clone, @@ -331,9 +330,8 @@ where /// Return `Ok` if the changed parameters are valid fn is_valid_parameter_change(&self) -> Result<()> { let validation_errors: Vec = - read_pos_params(&self.ctx.post()) + read_owned_pos_params(&self.ctx.post()) .map_err(Error::NativeVpError)? - .owned .validate(); validation_errors.is_empty().ok_or_else(|| { let validation_errors_str = diff --git a/crates/sdk/src/lib.rs b/crates/sdk/src/lib.rs index 5115746747c..463a4fd1538 100644 --- a/crates/sdk/src/lib.rs +++ b/crates/sdk/src/lib.rs @@ -918,8 +918,14 @@ pub mod testing { UpdateStewardCommission(UpdateStewardCommission), ResignSteward(Address), PendingTransfer(PendingTransfer), - IbcMsgTransfer(MsgTransfer, Option<(StoredBuildParams, String)>), - IbcMsgNftTransfer(MsgNftTransfer, Option<(StoredBuildParams, String)>), + IbcMsgTransfer( + MsgTransfer, + Option<(StoredBuildParams, String)>, + ), + IbcMsgNftTransfer( + MsgNftTransfer, + Option<(StoredBuildParams, String)>, + ), Custom, } @@ -1475,7 +1481,10 @@ pub mod testing { pub fn arb_msg_transfer()( message in arb_ibc_msg_transfer(), transfer_aux in option::of(arb_transfer()), - ) -> (MsgTransfer, Option<(ShieldedTransfer, HashMap, StoredBuildParams)>) { + ) -> ( + MsgTransfer, + Option<(ShieldedTransfer, HashMap, StoredBuildParams)>, + ) { if let Some((transfer, aux)) = transfer_aux { (MsgTransfer { message, transfer: Some(transfer) }, aux) } else { @@ -1522,7 +1531,10 @@ pub mod testing { pub fn arb_msg_nft_transfer()( message in arb_ibc_msg_nft_transfer(), transfer_aux in option::of(arb_transfer()), - ) -> (MsgNftTransfer, Option<(ShieldedTransfer, HashMap, StoredBuildParams)>) { + ) -> ( + MsgNftTransfer, + Option<(ShieldedTransfer, HashMap, StoredBuildParams)>, + ) { if let Some((transfer, aux)) = transfer_aux { (MsgNftTransfer { message, transfer: Some(transfer) }, aux) } else { diff --git a/crates/sdk/src/masp.rs b/crates/sdk/src/masp.rs index b5847d64295..ddedee83d44 100644 --- a/crates/sdk/src/masp.rs +++ b/crates/sdk/src/masp.rs @@ -2538,7 +2538,7 @@ fn extract_masp_tx_from_ibc_message( let tx_data = tx.data(cmt).ok_or_else(|| { Error::Other("Missing transaction data".to_string()) })?; - let ibc_msg = decode_message(&tx_data) + let ibc_msg = decode_message::(&tx_data) .map_err(|_| Error::Other("Invalid IBC message".to_string()))?; if let IbcMessage::Envelope(ref envelope) = ibc_msg { if let Some(masp_tx) = extract_masp_tx_from_envelope(envelope) { diff --git a/crates/sdk/src/queries/shell/eth_bridge.rs b/crates/sdk/src/queries/shell/eth_bridge.rs index dfcf33497cb..d3550c306dc 100644 --- a/crates/sdk/src/queries/shell/eth_bridge.rs +++ b/crates/sdk/src/queries/shell/eth_bridge.rs @@ -33,7 +33,6 @@ use namada_ethereum_bridge::storage::{ use namada_macros::BorshDeserializer; #[cfg(feature = "migrations")] use namada_migrations::*; -use namada_proof_of_stake::pos_queries::PosQueries; use namada_state::MembershipProof::BridgePool; use namada_state::{DBIter, StorageHasher, StoreRef, StoreType, DB}; use namada_storage::{CustomError, ResultExt, StorageRead}; @@ -43,6 +42,7 @@ use namada_vote_ext::validator_set_update::{ use serde::{Deserialize, Serialize}; use crate::eth_bridge::ethers::abi::AbiDecode; +use crate::governance; use crate::queries::{EncodedResponseQuery, RequestCtx, RequestQuery}; /// Container for the status of queried transfers to Ethereum. @@ -574,7 +574,7 @@ where let (validator_args, voting_powers) = ctx .state .ethbridge_queries() - .get_bridge_validator_set(None); + .get_bridge_validator_set::>(None); let relay_proof = ethereum_structs::RelayProof { transfers, pool_root: signed_root.data.0.0, @@ -667,7 +667,7 @@ where "Iterating over storage should not yield keys without \ values.", ) - .fractional_stake(ctx.state); + .fractional_stake::<_, _, governance::Store<_>>(ctx.state); for transfer in transfers { let key = get_key_from_hash(&transfer.keccak256()); let transfer = ctx @@ -757,7 +757,7 @@ where Ok(ctx .state .ethbridge_queries() - .get_bridge_validator_set(Some(epoch)) + .get_bridge_validator_set::>(Some(epoch)) .0) } } @@ -787,7 +787,7 @@ where Ok(ctx .state .ethbridge_queries() - .get_governance_validator_set(Some(epoch)) + .get_governance_validator_set::>(Some(epoch)) .0) } } @@ -802,7 +802,7 @@ where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, { - let maybe_epoch = ctx.state.pos_queries().get_epoch(height); + let maybe_epoch = ctx.state.get_epoch_at_height(height).unwrap(); let Some(epoch) = maybe_epoch else { return Err(namada_storage::Error::SimpleMessage( "The epoch of the requested height does not exist", @@ -830,7 +830,7 @@ where let (_, voting_powers) = ctx .state .ethbridge_queries() - .get_bridge_validator_set(Some(epoch)); + .get_bridge_validator_set::>(Some(epoch)); Ok(voting_powers) } @@ -850,6 +850,8 @@ mod test_ethbridge_router { }; use namada_ethereum_bridge::storage::proof::BridgePoolRootProof; use namada_ethereum_bridge::storage::whitelist; + use namada_ethereum_bridge::test_utils::GovStore; + use namada_proof_of_stake::queries::get_total_voting_power; use namada_storage::mockdb::MockDBWriteBatch; use namada_storage::StorageWrite; use namada_vote_ext::validator_set_update; @@ -886,17 +888,14 @@ mod test_ethbridge_router { .await .unwrap(); let expected = { - let total_power = client - .state - .pos_queries() - .get_total_voting_power(Some(epoch)) - .into(); + let total_power = + get_total_voting_power::<_, GovStore<_>>(&client.state, epoch) + .into(); let voting_powers_map: VotingPowersMap = client .state .ethbridge_queries() - .get_consensus_eth_addresses(Some(epoch)) - .iter() + .get_consensus_eth_addresses::>(epoch) .map(|(addr_book, _, power)| (addr_book, power)) .collect(); let (validators, voting_powers) = voting_powers_map @@ -976,7 +975,7 @@ mod test_ethbridge_router { .expect("Test failed") .eth_bridge, ); - let tx_result = aggregate_votes( + let tx_result = aggregate_votes::<_, _, GovStore<_>>( &mut client.state, validator_set_update::VextDigest::singleton(vext.clone()), 0.into(), @@ -1004,7 +1003,10 @@ mod test_ethbridge_router { client .state .ethbridge_queries() - .get_eth_addr_book(&established_address_1(), Some(0.into())) + .get_eth_addr_book::>( + &established_address_1(), + Some(0.into()), + ) .expect("Test failed"), vext.0.sig, ); @@ -1232,10 +1234,11 @@ mod test_ethbridge_router { .get_membership_proof(vec![transfer.clone()]) .expect("Test failed"); - let (validator_args, voting_powers) = client - .state - .ethbridge_queries() - .get_bridge_validator_set(None); + let (validator_args, voting_powers) = + client + .state + .ethbridge_queries() + .get_bridge_validator_set::>(None); let relay_proof = ethereum_structs::RelayProof { transfers: vec![(&transfer).into()], pool_root: signed_root.data.0.0, diff --git a/crates/sdk/src/queries/vp/pos.rs b/crates/sdk/src/queries/vp/pos.rs index 0072a84c8bc..208a2ad6f73 100644 --- a/crates/sdk/src/queries/vp/pos.rs +++ b/crates/sdk/src/queries/vp/pos.rs @@ -38,6 +38,7 @@ use namada_state::{DBIter, KeySeg, StorageHasher, DB}; use namada_storage::collections::lazy_map; use namada_storage::OptionExt; +use crate::governance; use crate::queries::types::RequestCtx; // PoS validity predicate queries @@ -189,7 +190,7 @@ where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, { - read_pos_params(ctx.state) + read_pos_params::<_, governance::Store<_>>(ctx.state) } /// Find if the given address belongs to a validator account. @@ -214,7 +215,7 @@ where H: 'static + StorageHasher + Sync, { let current_epoch = ctx.state.in_mem().last_epoch; - namada_proof_of_stake::storage::get_consensus_key( + namada_proof_of_stake::storage::get_consensus_key::<_, governance::Store<_>>( ctx.state, &addr, current_epoch, @@ -259,7 +260,7 @@ where H: 'static + StorageHasher + Sync, { let epoch = epoch.unwrap_or(ctx.state.in_mem().last_epoch); - let params = read_pos_params(ctx.state)?; + let params = read_pos_params::<_, governance::Store<_>>(ctx.state)?; let commission_rate = validator_commission_rate_handle(&validator) .get(ctx.state, epoch, ¶ms)?; let max_commission_change_per_epoch = @@ -313,9 +314,10 @@ where H: 'static + StorageHasher + Sync, { let epoch = epoch.unwrap_or(ctx.state.in_mem().last_epoch); - let state = namada_proof_of_stake::storage::read_validator_state( - ctx.state, &validator, &epoch, - )?; + let state = namada_proof_of_stake::storage::read_validator_state::< + _, + governance::Store<_>, + >(ctx.state, &validator, &epoch)?; Ok((state, epoch)) } @@ -346,7 +348,7 @@ where H: 'static + StorageHasher + Sync, { let epoch = epoch.unwrap_or(ctx.state.in_mem().last_epoch); - let params = read_pos_params(ctx.state)?; + let params = read_pos_params::<_, governance::Store<_>>(ctx.state)?; if namada_proof_of_stake::is_validator(ctx.state, &validator)? { let stake = read_validator_stake(ctx.state, ¶ms, &validator, epoch)?; @@ -407,7 +409,7 @@ where H: 'static + StorageHasher + Sync, { let epoch = epoch.unwrap_or(ctx.state.in_mem().last_epoch); - let params = read_pos_params(ctx.state)?; + let params = read_pos_params::<_, governance::Store<_>>(ctx.state)?; read_total_stake(ctx.state, ¶ms, epoch) } @@ -422,7 +424,7 @@ where H: 'static + StorageHasher + Sync, { let epoch = epoch.unwrap_or(ctx.state.in_mem().last_epoch); - let params = read_pos_params(ctx.state)?; + let params = read_pos_params::<_, governance::Store<_>>(ctx.state)?; read_total_active_stake(ctx.state, ¶ms, epoch) } @@ -450,7 +452,7 @@ where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, { - let params = read_pos_params(ctx.state)?; + let params = read_pos_params::<_, governance::Store<_>>(ctx.state)?; let epoch = epoch.unwrap_or( ctx.state .in_mem() @@ -477,7 +479,7 @@ where let epoch = epoch.unwrap_or(ctx.state.in_mem().last_epoch); let bond_id = BondId { source, validator }; - bond_amount(ctx.state, &bond_id, epoch) + bond_amount::<_, governance::Store<_>>(ctx.state, &bond_id, epoch) } fn unbond( @@ -570,7 +572,12 @@ where H: 'static + StorageHasher + Sync, { let current_epoch = ctx.state.in_mem().last_epoch; - query_reward_tokens(ctx.state, source.as_ref(), &validator, current_epoch) + query_reward_tokens::<_, governance::Store<_>>( + ctx.state, + source.as_ref(), + &validator, + current_epoch, + ) } fn bonds_and_unbonds( @@ -582,7 +589,7 @@ where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, { - namada_proof_of_stake::queries::bonds_and_unbonds( + namada_proof_of_stake::queries::bonds_and_unbonds::<_, governance::Store<_>>( ctx.state, source, validator, ) } @@ -614,7 +621,7 @@ where H: 'static + StorageHasher + Sync, { let epoch: Epoch = epoch.unwrap_or(ctx.state.in_mem().last_epoch); - find_delegations(ctx.state, &owner, &epoch) + find_delegations::<_, governance::Store<_>>(ctx.state, &owner, &epoch) } /// Validator slashes @@ -694,7 +701,9 @@ where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, { - namada_proof_of_stake::queries::has_bonds(ctx.state, &source) + namada_proof_of_stake::queries::has_bonds::<_, governance::Store<_>>( + ctx.state, &source, + ) } /// Client-only methods for the router type are composed from router functions. diff --git a/crates/sdk/src/signing.rs b/crates/sdk/src/signing.rs index 3e5e3a3c6a1..57bf85a872a 100644 --- a/crates/sdk/src/signing.rs +++ b/crates/sdk/src/signing.rs @@ -1319,7 +1319,9 @@ pub async fn to_ledger_vector( .data(cmt) .ok_or_else(|| Error::Other("Invalid Data".to_string()))?; - if let Ok(transfer) = MsgTransfer::try_from_slice(data.as_ref()) { + if let Ok(transfer) = + MsgTransfer::::try_from_slice(data.as_ref()) + { tv.name = "IBC_Transfer_0".to_string(); tv.output.push("Type : IBC Transfer".to_string()); let transfer_token = format!( @@ -1408,7 +1410,7 @@ pub async fn to_ledger_vector( .await?; } } else if let Ok(transfer) = - MsgNftTransfer::try_from_slice(data.as_ref()) + MsgNftTransfer::::try_from_slice(data.as_ref()) { tv.name = "IBC_NFT_Transfer_0".to_string(); tv.output.push("Type : IBC NFT Transfer".to_string()); diff --git a/crates/sdk/src/validation.rs b/crates/sdk/src/validation.rs index b5e2643cc64..c1c8d8ab138 100644 --- a/crates/sdk/src/validation.rs +++ b/crates/sdk/src/validation.rs @@ -30,10 +30,13 @@ pub type IbcVp<'a, S, CA> = ibc::vp::Ibc< S, VpCache, Eval, + ParamsIbcVpStore<'a, S, CA>, ParamsPreStore<'a, S, CA>, + ParamsIbcPseudoStore<'a, S, CA>, GovPreStore<'a, S, CA>, TokenStoreForIbcExec<'a, S, CA>, PosPreStore<'a, S, CA>, + token::Transfer, >; /// IBC VP pseudo-execution context @@ -90,6 +93,7 @@ pub type MaspVp<'a, S, CA> = token::vp::MaspVp< GovPreStore<'a, S, CA>, IbcPostStore<'a, S, CA>, TokenPreStore<'a, S, CA>, + token::Transfer, >; /// Native ETH bridge VP @@ -136,6 +140,22 @@ pub type TokenStoreForIbcExec<'a, S, CA> = token::Store< >, >; +/// Parameters store implementation over the native prior context +pub type ParamsIbcVpStore<'a, S, CA> = parameters::Store< + ibc::vp::context::VpValidationContext<'a, 'a, S, VpCache, Eval>, +>; + +/// Parameters store implementation over the native prior context +pub type ParamsIbcPseudoStore<'a, S, CA> = parameters::Store< + ibc::vp::context::PseudoExecutionStorage< + 'a, + 'a, + S, + VpCache, + Eval, + >, +>; + /// Token storage keys implementation pub type TokenKeys = token::Store<()>; diff --git a/crates/shielded_token/src/vp.rs b/crates/shielded_token/src/vp.rs index ed47f1a97f4..4f9861d79a2 100644 --- a/crates/shielded_token/src/vp.rs +++ b/crates/shielded_token/src/vp.rs @@ -4,6 +4,7 @@ use std::cmp::Ordering; use std::collections::{BTreeMap, BTreeSet}; use std::marker::PhantomData; +use borsh::BorshDeserialize; use masp_primitives::asset_type::AssetType; use masp_primitives::merkle_tree::CommitmentTree; use masp_primitives::sapling::Node; @@ -49,15 +50,14 @@ pub enum Error { pub type Result = std::result::Result; /// MASP VP -pub struct MaspVp<'ctx, S, CA, EVAL, Params, Gov, Ibc, TransToken> +pub struct MaspVp<'ctx, S, CA, EVAL, Params, Gov, Ibc, TransToken, Transfer> where S: 'static + StateRead, - EVAL: VpEvaluator<'ctx, S, CA, EVAL>, { /// Context to interact with the host structures. pub ctx: Ctx<'ctx, S, CA, EVAL>, /// Generic types for DI - pub _marker: PhantomData<(Params, Gov, Ibc, TransToken)>, + pub _marker: PhantomData<(Params, Gov, Ibc, TransToken, Transfer)>, } // The balances changed by the transaction, split between masp and non-masp @@ -73,8 +73,8 @@ struct ChangedBalances { post: BTreeMap>, } -impl<'view, 'ctx: 'view, S, CA, EVAL, Params, Gov, Ibc, TransToken> - MaspVp<'ctx, S, CA, EVAL, Params, Gov, Ibc, TransToken> +impl<'view, 'ctx: 'view, S, CA, EVAL, Params, Gov, Ibc, TransToken, Transfer> + MaspVp<'ctx, S, CA, EVAL, Params, Gov, Ibc, TransToken, Transfer> where S: 'static + StateRead, CA: 'static + Clone, @@ -84,6 +84,7 @@ where Ibc: ibc::Read>, TransToken: trans_token::Keys + trans_token::Read>, + Transfer: BorshDeserialize, { /// Instantiate MASP VP pub fn new(ctx: Ctx<'ctx, S, CA, EVAL>) -> Self { @@ -373,7 +374,7 @@ where post, } = changed_balances; let ibc::ChangedBalances { decoder, pre, post } = - Ibc::apply_ibc_packet( + Ibc::apply_ibc_packet::( &self.ctx.post(), tx_data, ibc::ChangedBalances { decoder, pre, post }, @@ -409,29 +410,30 @@ where .data(batched_tx.cmt) .ok_or_err_msg("No transaction data")?; let actions = self.ctx.read_actions()?; - let shielded_tx = - if let Some(tx) = Ibc::try_extract_masp_tx_from_envelope(&tx_data)? - { - tx - } else { - // Get the Transaction object from the actions - let masp_section_ref = - namada_tx::action::get_masp_section_ref(&actions) - .ok_or_else(|| { - native_vp::Error::new_const( - "Missing MASP section reference in action", - ) - })?; - batched_tx - .tx - .get_masp_section(&masp_section_ref) - .cloned() - .ok_or_else(|| { - native_vp::Error::new_const( - "Missing MASP section in transaction", - ) - })? - }; + let shielded_tx = if let Some(tx) = + Ibc::try_extract_masp_tx_from_envelope::(&tx_data)? + { + tx + } else { + // Get the Transaction object from the actions + let masp_section_ref = namada_tx::action::get_masp_section_ref( + &actions, + ) + .ok_or_else(|| { + native_vp::Error::new_const( + "Missing MASP section reference in action", + ) + })?; + batched_tx + .tx + .get_masp_section(&masp_section_ref) + .cloned() + .ok_or_else(|| { + native_vp::Error::new_const( + "Missing MASP section in transaction", + ) + })? + }; if u64::from(self.ctx.get_block_height()?) > u64::from(shielded_tx.expiry_height()) @@ -915,8 +917,9 @@ fn verify_sapling_balancing_value( } } -impl<'view, 'ctx: 'view, S, CA, EVAL, Params, Gov, Ibc, TransToken> - NativeVp<'view> for MaspVp<'ctx, S, CA, EVAL, Params, Gov, Ibc, TransToken> +impl<'view, 'ctx: 'view, S, CA, EVAL, Params, Gov, Ibc, TransToken, Transfer> + NativeVp<'view> + for MaspVp<'ctx, S, CA, EVAL, Params, Gov, Ibc, TransToken, Transfer> where S: 'static + StateRead, CA: 'static + Clone, @@ -926,6 +929,7 @@ where Ibc: ibc::Read>, TransToken: trans_token::Keys + trans_token::Read>, + Transfer: BorshDeserialize, { type Error = Error; diff --git a/crates/systems/src/governance.rs b/crates/systems/src/governance.rs index b6857b0eb56..19e190eea45 100644 --- a/crates/systems/src/governance.rs +++ b/crates/systems/src/governance.rs @@ -6,4 +6,13 @@ pub use namada_storage::Result; pub trait Read { /// Check if an accepted proposal is being executed fn is_proposal_accepted(storage: &S, tx_data: &[u8]) -> Result; + + /// Get governance "max_proposal_period" parameter + fn max_proposal_period(storage: &S) -> Result; +} + +/// Abstract governance storage write interface +pub trait Write: Read { + /// Initialize default governance parameters into storage + fn init_default_params(storage: &mut S) -> Result<()>; } diff --git a/crates/systems/src/ibc.rs b/crates/systems/src/ibc.rs index 970ceac9995..549865104e5 100644 --- a/crates/systems/src/ibc.rs +++ b/crates/systems/src/ibc.rs @@ -5,6 +5,7 @@ use std::collections::{BTreeMap, BTreeSet}; use masp_primitives::transaction::components::ValueSum; use masp_primitives::transaction::TransparentAddress; use namada_core::address::Address; +use namada_core::borsh::BorshDeserialize; use namada_core::masp::TAddrData; use namada_core::{masp_primitives, storage, token}; pub use namada_storage::Result; @@ -12,12 +13,12 @@ pub use namada_storage::Result; /// Abstract IBC storage read interface pub trait Read { /// Extract MASP transaction from IBC envelope - fn try_extract_masp_tx_from_envelope( + fn try_extract_masp_tx_from_envelope( tx_data: &[u8], ) -> Result>; /// Apply relevant IBC packets to the changed balances structure - fn apply_ibc_packet( + fn apply_ibc_packet( storage: &S, tx_data: &[u8], acc: ChangedBalances, diff --git a/crates/systems/src/parameters.rs b/crates/systems/src/parameters.rs index 9a968c2b107..6dc746a0511 100644 --- a/crates/systems/src/parameters.rs +++ b/crates/systems/src/parameters.rs @@ -2,6 +2,8 @@ pub use namada_core::parameters::*; use namada_core::storage; +use namada_core::storage::BlockHeight; +use namada_core::time::DurationSecs; pub use namada_storage::Result; /// Abstract parameters storage keys interface @@ -26,6 +28,15 @@ pub trait Read { /// Read the number of epochs per year parameter fn epochs_per_year(storage: &S) -> Result; + + /// Return an estimate of the maximum time taken to decide a block, + /// by sourcing block headers from up to `num_blocks_to_read`, and + /// from chain parameters. + fn estimate_max_block_time_from_blocks_and_params( + storage: &S, + last_block_height: BlockHeight, + num_blocks_to_read: u64, + ) -> Result; } /// Abstract parameters storage write interface diff --git a/crates/systems/src/test.rs b/crates/systems/src/test.rs index 4d3d0f71e03..8cb29855687 100644 --- a/crates/systems/src/test.rs +++ b/crates/systems/src/test.rs @@ -8,7 +8,9 @@ lazy_static! { static ref SYSTEMS: HashSet<&'static str> = HashSet::from_iter([ "namada_governance", + "namada_ibc", "namada_parameters", + "namada_proof_of_stake", "namada_shielded_token", "namada_token", "namada_trans_token", diff --git a/crates/systems/src/trans_token.rs b/crates/systems/src/trans_token.rs index 7793e6046d1..16440d3f2ff 100644 --- a/crates/systems/src/trans_token.rs +++ b/crates/systems/src/trans_token.rs @@ -1,5 +1,7 @@ //! Transparent token abstract interfaces +use std::borrow::Cow; + use namada_core::address::Address; pub use namada_core::token::*; use namada_core::{storage, token}; @@ -89,3 +91,24 @@ pub trait Write: Read { amount: token::Amount, ) -> Result<()>; } + +/// Abstract token events interface +pub trait Events: Read { + /// Emit mint token event + fn emit_mint_event( + storage: &mut S, + descriptor: Cow<'static, str>, + token: &Address, + amount: token::Amount, + target: &Address, + ) -> Result<()>; + + /// Emit burn token event + fn emit_burn_event( + storage: &mut S, + descriptor: Cow<'static, str>, + token: &Address, + amount: token::Amount, + target: &Address, + ) -> Result<()>; +} diff --git a/crates/tests/src/native_vp/pos.rs b/crates/tests/src/native_vp/pos.rs index b0ae83a1583..59b7ca736f9 100644 --- a/crates/tests/src/native_vp/pos.rs +++ b/crates/tests/src/native_vp/pos.rs @@ -130,7 +130,12 @@ pub fn init_pos( // .state // .init_genesis(params, genesis_validators.iter(), start_epoch) // .unwrap(); - let params = init_genesis( + let params = init_genesis::< + _, + crate::parameters::Store<_>, + crate::governance::Store<_>, + crate::token::Store<_>, + >( &mut tx_env.state, params.clone(), genesis_validators.iter().cloned(), @@ -150,6 +155,7 @@ mod tests { use std::cell::RefCell; use namada_sdk::gas::VpGasMeter; + use namada_sdk::governance::parameters::GovernanceParameters; use namada_sdk::key::common::PublicKey; use namada_sdk::validation::PosVp; use namada_sdk::{address, token}; @@ -336,7 +342,11 @@ mod tests { // We're starting from an empty state let state = vec![]; let epoch = Epoch(epoch); - let params = params.with_default_gov_params(); + let params = PosParams { + owned: params, + max_proposal_period: GovernanceParameters::default() + .max_proposal_period, + }; arb_valid_pos_action(&state).prop_map(move |valid_action| { Self { epoch, @@ -594,7 +604,7 @@ pub mod testing { use namada_sdk::proof_of_stake::ADDRESS as POS_ADDRESS; use namada_sdk::storage::Epoch; use namada_sdk::token::{Amount, Change}; - use namada_sdk::{address, key, token}; + use namada_sdk::{address, governance, key, token}; use namada_tx_prelude::{Address, StorageRead, StorageWrite}; use proptest::prelude::*; @@ -861,7 +871,8 @@ pub mod testing { /// the VP. pub fn apply(self, is_current_tx_valid: bool) { // Read the PoS parameters - let params = read_pos_params(tx::ctx()).unwrap(); + let params = + read_pos_params::<_, governance::Store<_>>(tx::ctx()).unwrap(); let current_epoch = tx_host_env::with(|env| { // Reset the gas meter on each change, so that we never run @@ -1575,7 +1586,8 @@ pub mod testing { /// Apply an invalid PoS storage action. pub fn apply(self) { // Read the PoS parameters - let params = read_pos_params(tx::ctx()).unwrap(); + let params = + read_pos_params::<_, governance::Store<_>>(tx::ctx()).unwrap(); for (epoch, changes) in self.changes { for change in changes { diff --git a/crates/tests/src/vm_host_env/ibc.rs b/crates/tests/src/vm_host_env/ibc.rs index b6cc717dfce..654442dbe2f 100644 --- a/crates/tests/src/vm_host_env/ibc.rs +++ b/crates/tests/src/vm_host_env/ibc.rs @@ -214,7 +214,13 @@ pub fn init_storage() -> (Address, Address) { ), }; ibc_params.init_storage(&mut env.state).unwrap(); - proof_of_stake::test_utils::test_init_genesis( + + proof_of_stake::test_utils::test_init_genesis::< + _, + crate::parameters::Store<_>, + crate::governance::Store<_>, + crate::token::Store<_>, + >( &mut env.state, OwnedPosParams::default(), vec![get_dummy_genesis_validator()].into_iter(), @@ -606,7 +612,7 @@ pub fn msg_transfer( channel_id: ChannelId, denom: String, sender: &Address, -) -> MsgTransfer { +) -> MsgTransfer { let timestamp = (Timestamp::now() + Duration::from_secs(100)).unwrap(); let message = IbcMsgTransfer { port_id_on_a: port_id, diff --git a/crates/tests/src/vm_host_env/mod.rs b/crates/tests/src/vm_host_env/mod.rs index 290b4a65afa..2dd015cc077 100644 --- a/crates/tests/src/vm_host_env/mod.rs +++ b/crates/tests/src/vm_host_env/mod.rs @@ -698,7 +698,7 @@ mod tests { // create a client with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("creating a client failed"); // Check @@ -731,7 +731,7 @@ mod tests { .sign_wrapper(keypair); // update the client with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("updating a client failed"); // Check @@ -774,7 +774,7 @@ mod tests { .sign_wrapper(keypair.clone()); // init a connection with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("creating a connection failed"); // Check @@ -807,7 +807,7 @@ mod tests { .sign_wrapper(keypair); // open the connection with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("opening the connection failed"); // Check @@ -851,7 +851,7 @@ mod tests { .sign_wrapper(keypair.clone()); // open try a connection with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("creating a connection failed"); // Check @@ -884,7 +884,7 @@ mod tests { .sign_wrapper(keypair); // open the connection with the mssage tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("opening the connection failed"); // Check @@ -930,7 +930,7 @@ mod tests { .sign_wrapper(keypair.clone()); // init a channel with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("creating a channel failed"); // Check @@ -963,7 +963,7 @@ mod tests { .sign_wrapper(keypair); // open the channel with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("opening the channel failed"); // Check @@ -1009,7 +1009,7 @@ mod tests { .sign_wrapper(keypair.clone()); // try open a channel with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("creating a channel failed"); // Check @@ -1043,7 +1043,7 @@ mod tests { .sign_wrapper(keypair); // open a channel with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("opening the channel failed"); // Check @@ -1098,7 +1098,7 @@ mod tests { let dummy_module = DummyNftTransferModule {}; actions.add_transfer_module(dummy_module); actions - .execute(&tx_data) + .execute::(&tx_data) .expect("closing the channel failed"); // Check @@ -1152,7 +1152,7 @@ mod tests { // close the channel with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("closing the channel failed"); // Check @@ -1201,7 +1201,7 @@ mod tests { .sign_wrapper(keypair.clone()); // send the token and a packet with the data tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("sending a token failed"); // Check @@ -1251,7 +1251,7 @@ mod tests { .sign_wrapper(keypair); // ack the packet with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("ack failed"); // Check @@ -1338,7 +1338,7 @@ mod tests { .sign_wrapper(keypair); // send the token and a packet with the data tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("sending a token failed"); // Check @@ -1422,7 +1422,7 @@ mod tests { .sign_wrapper(keypair); // receive a packet with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("receiving the token failed"); // Check @@ -1517,7 +1517,7 @@ mod tests { .sign_wrapper(keypair); // Receive the packet, but no token is received tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("receiving the token failed"); // Check if the transaction is valid @@ -1612,7 +1612,7 @@ mod tests { .sign_wrapper(keypair); // receive a packet with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("receiving a token failed"); // Check @@ -1716,7 +1716,7 @@ mod tests { .sign_wrapper(keypair); // receive a packet with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("receiving a token failed"); // Check @@ -1780,7 +1780,7 @@ mod tests { let tx_data = msg.serialize_to_vec(); // send a packet with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("sending a token failed"); // Commit @@ -1812,7 +1812,7 @@ mod tests { // timeout the packet tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("timeout failed"); // Check @@ -1866,7 +1866,7 @@ mod tests { let tx_data = msg.serialize_to_vec(); // send a packet with the message tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("sending a token failed"); // Commit @@ -1898,7 +1898,7 @@ mod tests { // timeout the packet tx_host_env::ibc::ibc_actions(tx::ctx()) - .execute(&tx_data) + .execute::(&tx_data) .expect("timeout on close failed"); // Check diff --git a/crates/trans_token/src/lib.rs b/crates/trans_token/src/lib.rs index b9cc0bdea7d..024004972af 100644 --- a/crates/trans_token/src/lib.rs +++ b/crates/trans_token/src/lib.rs @@ -24,8 +24,12 @@ pub mod vp; use std::marker::PhantomData; +use event::{TokenEvent, TokenOperation}; use namada_core::address::Address; use namada_core::token; +use namada_core::uint::Uint; +use namada_events::extend::UserAccount; +use namada_events::{EmitEvents, EventLevel}; use namada_storage::{StorageRead, StorageWrite}; pub use namada_systems::trans_token::*; pub use storage::*; @@ -125,3 +129,54 @@ where storage::credit_tokens(storage, token, dest, amount) } } + +impl Events for Store +where + S: StorageRead + EmitEvents, +{ + fn emit_mint_event( + storage: &mut S, + descriptor: std::borrow::Cow<'static, str>, + token: &Address, + amount: token::Amount, + target: &Address, + ) -> Result<()> { + let post_balance: Uint = + Self::read_balance(storage, token, target)?.into(); + + storage.emit(TokenEvent { + descriptor, + level: EventLevel::Tx, + operation: TokenOperation::Mint { + token: token.clone(), + amount: amount.into(), + post_balance, + target_account: UserAccount::Internal(target.clone()), + }, + }); + Ok(()) + } + + fn emit_burn_event( + storage: &mut S, + descriptor: std::borrow::Cow<'static, str>, + token: &Address, + amount: token::Amount, + target: &Address, + ) -> Result<()> { + let post_balance: Uint = + Self::read_balance(storage, token, target)?.into(); + + storage.emit(TokenEvent { + descriptor, + level: EventLevel::Tx, + operation: TokenOperation::Burn { + token: token.clone(), + amount: amount.into(), + post_balance, + target_account: UserAccount::Internal(target.clone()), + }, + }); + Ok(()) + } +} diff --git a/crates/trans_token/src/storage.rs b/crates/trans_token/src/storage.rs index da74b83595f..574799d38c6 100644 --- a/crates/trans_token/src/storage.rs +++ b/crates/trans_token/src/storage.rs @@ -334,7 +334,7 @@ where S: StorageRead + StorageWrite, { credit_tokens(storage, token, dest, amount)?; - storage.write(&minter_key(token), minter.clone()) + storage.write(&minter_key(token), minter) } /// Credit tokens to an account, to be used only by protocol. In transactions, diff --git a/crates/trans_token/src/vp.rs b/crates/trans_token/src/vp.rs index 24c49fff4d8..af56a308230 100644 --- a/crates/trans_token/src/vp.rs +++ b/crates/trans_token/src/vp.rs @@ -49,7 +49,6 @@ pub type Result = std::result::Result; pub struct MultitokenVp<'ctx, S, CA, EVAL, Params, Gov> where S: 'static + StateRead, - EVAL: VpEvaluator<'ctx, S, CA, EVAL>, { /// Context to interact with the host structures. pub ctx: Ctx<'ctx, S, CA, EVAL>, diff --git a/crates/tx_prelude/src/ibc.rs b/crates/tx_prelude/src/ibc.rs index 8e83088ab91..d82cedc461b 100644 --- a/crates/tx_prelude/src/ibc.rs +++ b/crates/tx_prelude/src/ibc.rs @@ -23,13 +23,16 @@ use crate::{Ctx, Error}; /// IBC actions to handle an IBC message. The `verifiers` inserted into the set /// must be inserted into the tx context with `Ctx::insert_verifier` after tx /// execution. -pub fn ibc_actions(ctx: &mut Ctx) -> IbcActions<'_, Ctx> { +pub fn ibc_actions( + ctx: &mut Ctx, +) -> IbcActions<'_, Ctx, crate::parameters::Store, crate::token::Store> +{ let ctx = Rc::new(RefCell::new(ctx.clone())); let verifiers = Rc::new(RefCell::new(BTreeSet::
::new())); let mut actions = IbcActions::new(ctx.clone(), verifiers.clone()); let module = TransferModule::new(ctx.clone(), verifiers); actions.add_transfer_module(module); - let module = NftTransferModule::new(ctx); + let module = NftTransferModule::>::new(ctx); actions.add_transfer_module(module); actions } @@ -72,7 +75,7 @@ impl IbcStorageContext for Ctx { token: &Address, amount: Amount, ) -> Result<(), Error> { - mint_tokens(self, target, token, amount) + mint_tokens::<_, crate::token::Store<_>>(self, target, token, amount) } fn burn_token( @@ -81,7 +84,7 @@ impl IbcStorageContext for Ctx { token: &Address, amount: Amount, ) -> Result<(), Error> { - burn_tokens(self, target, token, amount) + burn_tokens::<_, crate::token::Store<_>>(self, target, token, amount) } fn insert_verifier(&mut self, addr: &Address) -> Result<(), Error> { diff --git a/crates/tx_prelude/src/proof_of_stake.rs b/crates/tx_prelude/src/proof_of_stake.rs index 72b376a1841..33e239b3818 100644 --- a/crates/tx_prelude/src/proof_of_stake.rs +++ b/crates/tx_prelude/src/proof_of_stake.rs @@ -1,7 +1,7 @@ //! Proof of Stake system integration with functions for transactions use namada_core::dec::Dec; -use namada_core::{key, token}; +use namada_core::key; pub use namada_proof_of_stake::parameters::PosParams; pub use namada_proof_of_stake::queries::find_delegation_validators; use namada_proof_of_stake::storage::read_pos_params; @@ -19,6 +19,7 @@ use namada_tx::action::{ use namada_tx::data::pos::{BecomeValidator, Bond}; use super::*; +use crate::token; impl Ctx { /// Self-bond tokens to a validator when `source` is `None` or equal to @@ -41,7 +42,14 @@ impl Ctx { })))?; let current_epoch = self.get_block_epoch()?; - bond_tokens(self, source, validator, amount, current_epoch, None) + bond_tokens::<_, governance::Store<_>, token::Store<_>>( + self, + source, + validator, + amount, + current_epoch, + None, + ) } /// Unbond self-bonded tokens from a validator when `source` is `None` @@ -64,7 +72,14 @@ impl Ctx { })))?; let current_epoch = self.get_block_epoch()?; - unbond_tokens(self, source, validator, amount, current_epoch, false) + unbond_tokens::<_, governance::Store<_>>( + self, + source, + validator, + amount, + current_epoch, + false, + ) } /// Withdraw unbonded tokens from a self-bond to a validator when @@ -85,7 +100,12 @@ impl Ctx { })))?; let current_epoch = self.get_block_epoch()?; - withdraw_tokens(self, source, validator, current_epoch) + withdraw_tokens::<_, governance::Store<_>, token::Store<_>>( + self, + source, + validator, + current_epoch, + ) } /// Change validator consensus key. @@ -102,7 +122,12 @@ impl Ctx { )))?; let current_epoch = self.get_block_epoch()?; - change_consensus_key(self, validator, consensus_key, current_epoch) + change_consensus_key::<_, governance::Store<_>>( + self, + validator, + consensus_key, + current_epoch, + ) } /// Change validator commission rate. @@ -119,7 +144,12 @@ impl Ctx { )))?; let current_epoch = self.get_block_epoch()?; - change_validator_commission_rate(self, validator, *rate, current_epoch) + change_validator_commission_rate::<_, governance::Store<_>>( + self, + validator, + *rate, + current_epoch, + ) } /// Unjail a jailed validator and re-enter the validator sets. @@ -130,7 +160,11 @@ impl Ctx { self.push_action(Action::Pos(PosAction::Unjail(validator.clone())))?; let current_epoch = self.get_block_epoch()?; - unjail_validator(self, validator, current_epoch) + unjail_validator::<_, governance::Store<_>>( + self, + validator, + current_epoch, + ) } /// Redelegate bonded tokens from one validator to another one. @@ -152,7 +186,7 @@ impl Ctx { })))?; let current_epoch = self.get_block_epoch()?; - redelegate_tokens( + redelegate_tokens::<_, governance::Store<_>>( self, owner, src_validator, @@ -178,7 +212,12 @@ impl Ctx { })))?; let current_epoch = self.get_block_epoch()?; - claim_reward_tokens(self, source, validator, current_epoch) + claim_reward_tokens::<_, governance::Store<_>, token::Store<_>>( + self, + source, + validator, + current_epoch, + ) } /// Attempt to initialize a validator account. On success, returns the @@ -204,7 +243,7 @@ impl Ctx { let current_epoch = self.get_block_epoch()?; let eth_cold_key = key::common::PublicKey::Secp256k1(eth_cold_key); let eth_hot_key = key::common::PublicKey::Secp256k1(eth_hot_key); - let params = read_pos_params(self)?; + let params = read_pos_params::<_, governance::Store<_>>(self)?; // The tx must be authorized by the source address self.insert_verifier(&address)?; @@ -213,7 +252,7 @@ impl Ctx { address.clone(), )))?; - become_validator( + become_validator::<_, governance::Store<_>>( self, namada_proof_of_stake::BecomeValidator { params: ¶ms, @@ -250,7 +289,11 @@ impl Ctx { )))?; let current_epoch = self.get_block_epoch()?; - deactivate_validator(self, validator, current_epoch) + deactivate_validator::<_, governance::Store<_>>( + self, + validator, + current_epoch, + ) } /// Reactivate validator @@ -263,7 +306,11 @@ impl Ctx { )))?; let current_epoch = self.get_block_epoch()?; - reactivate_validator(self, validator, current_epoch) + reactivate_validator::<_, governance::Store<_>>( + self, + validator, + current_epoch, + ) } /// Change validator metadata. @@ -287,7 +334,7 @@ impl Ctx { )))?; let current_epoch = self.get_block_epoch()?; - change_validator_metadata( + change_validator_metadata::<_, governance::Store<_>>( self, validator, email, diff --git a/crates/vm/src/host_env.rs b/crates/vm/src/host_env.rs index e928de6afe4..61cbf89ac0a 100644 --- a/crates/vm/src/host_env.rs +++ b/crates/vm/src/host_env.rs @@ -90,7 +90,6 @@ pub struct TxVmEnv where D: DB + for<'iter> DBIter<'iter>, H: StorageHasher, - CA: WasmCacheAccess, { /// The VM memory for bi-directional data passing pub memory: MEM, @@ -104,7 +103,6 @@ pub struct TxCtx where D: DB + for<'iter> DBIter<'iter>, H: StorageHasher, - CA: WasmCacheAccess, { /// Mutable access to write log. pub write_log: HostRef, @@ -302,8 +300,6 @@ pub struct VpVmEnv where D: DB + for<'iter> DBIter<'iter>, H: StorageHasher, - EVAL: VpEvaluator, - CA: WasmCacheAccess, { /// The VM memory for bi-directional data passing pub memory: MEM, @@ -316,8 +312,6 @@ pub struct VpCtx where D: DB + for<'iter> DBIter<'iter>, H: StorageHasher, - EVAL: VpEvaluator, - CA: WasmCacheAccess, { /// The address of the account that owns the VP pub address: HostRef, diff --git a/crates/vm/src/wasm/compilation_cache/common.rs b/crates/vm/src/wasm/compilation_cache/common.rs index 75708a1a2fa..43a2cd35c15 100644 --- a/crates/vm/src/wasm/compilation_cache/common.rs +++ b/crates/vm/src/wasm/compilation_cache/common.rs @@ -25,7 +25,7 @@ use crate::{WasmCacheAccess, WasmCacheRoAccess}; /// Cache handle. Thread-safe. #[derive(Debug, Clone)] -pub struct Cache { +pub struct Cache { /// Cached files directory dir: PathBuf, /// Compilation progress diff --git a/crates/vp/src/native_vp.rs b/crates/vp/src/native_vp.rs index dde8eafb58c..ce2c95264c4 100644 --- a/crates/vp/src/native_vp.rs +++ b/crates/vp/src/native_vp.rs @@ -54,7 +54,6 @@ pub trait NativeVp<'a> { pub struct Ctx<'a, S, CA, EVAL> where S: StateRead, - EVAL: VpEvaluator<'a, S, CA, EVAL>, { /// The address of the account that owns the VP pub address: &'a Address, @@ -86,7 +85,6 @@ where pub trait VpEvaluator<'a, S, CA, EVAL> where S: 'a + StateRead, - EVAL: VpEvaluator<'a, S, CA, EVAL>, { /// Evaluate a given validity predicate code with the given input data. /// Currently, we can only evaluate VPs using WASM runner with WASM memory. @@ -106,7 +104,6 @@ where pub struct CtxPreStorageRead<'view, 'a, S, CA, EVAL> where S: StateRead, - EVAL: VpEvaluator<'a, S, CA, EVAL>, { /// The inner context pub ctx: &'view Ctx<'a, S, CA, EVAL>, @@ -118,7 +115,6 @@ where pub struct CtxPostStorageRead<'view, 'a, S, CA, EVAL> where S: StateRead, - EVAL: VpEvaluator<'a, S, CA, EVAL>, { /// The inner context pub ctx: &'view Ctx<'a, S, CA, EVAL>, diff --git a/wasm/Cargo.lock b/wasm/Cargo.lock index 116101ab91f..bfdb477cb89 100644 --- a/wasm/Cargo.lock +++ b/wasm/Cargo.lock @@ -3569,6 +3569,7 @@ dependencies = [ "namada_account", "namada_core", "namada_events", + "namada_governance", "namada_macros", "namada_parameters", "namada_proof_of_stake", @@ -3648,13 +3649,10 @@ dependencies = [ "namada_core", "namada_events", "namada_gas", - "namada_governance", "namada_macros", - "namada_parameters", "namada_state", "namada_storage", "namada_systems", - "namada_token", "namada_tx", "namada_vp", "primitive-types", @@ -3719,13 +3717,10 @@ dependencies = [ "namada_controller", "namada_core", "namada_events", - "namada_governance", "namada_macros", - "namada_parameters", "namada_state", "namada_storage", "namada_systems", - "namada_trans_token", "namada_tx", "namada_vp", "once_cell", diff --git a/wasm/tx_ibc/src/lib.rs b/wasm/tx_ibc/src/lib.rs index a3e11558748..5f36976dc4e 100644 --- a/wasm/tx_ibc/src/lib.rs +++ b/wasm/tx_ibc/src/lib.rs @@ -11,8 +11,9 @@ use namada_tx_prelude::*; #[transaction] fn apply_tx(ctx: &mut Ctx, tx_data: BatchedTx) -> TxResult { let data = ctx.get_tx_data(&tx_data)?; - let (transfer, masp_tx) = - ibc::ibc_actions(ctx).execute(&data).into_storage_result()?; + let (transfer, masp_tx) = ibc::ibc_actions(ctx) + .execute::(&data) + .into_storage_result()?; let masp_section_ref = if let Some(transfers) = transfer { // Prepare the sources of the multi-transfer diff --git a/wasm/vp_implicit/src/lib.rs b/wasm/vp_implicit/src/lib.rs index de6a44b5f04..f8f07845446 100644 --- a/wasm/vp_implicit/src/lib.rs +++ b/wasm/vp_implicit/src/lib.rs @@ -259,7 +259,7 @@ mod tests { use namada_tests::vp::*; // Use this as `#[test]` annotation to enable logging use namada_tx_prelude::dec::Dec; - use namada_tx_prelude::proof_of_stake::parameters::PosParams; + use namada_tx_prelude::proof_of_stake::parameters::OwnedPosParams; use namada_tx_prelude::proof_of_stake::types::GenesisValidator; use namada_tx_prelude::storage::Epoch; use namada_tx_prelude::{StorageWrite, TxEnv}; @@ -487,7 +487,7 @@ mod tests { #[test] fn test_unsigned_pos_action_rejected() { // Init PoS genesis - let pos_params = PosParams::default(); + let pos_params = OwnedPosParams::default(); let validator = address::testing::established_address_3(); let initial_stake = token::Amount::from_uint(10_098_123, 0).unwrap(); let consensus_key = key::testing::keypair_2().ref_to(); @@ -581,7 +581,7 @@ mod tests { #[test] fn test_signed_pos_action_accepted() { // Init PoS genesis - let pos_params = PosParams::default(); + let pos_params = OwnedPosParams::default(); let validator = address::testing::established_address_3(); let initial_stake = token::Amount::from_uint(10_098_123, 0).unwrap(); let consensus_key = key::testing::keypair_2().ref_to(); diff --git a/wasm/vp_user/src/lib.rs b/wasm/vp_user/src/lib.rs index 395e213cdfd..ef577eac204 100644 --- a/wasm/vp_user/src/lib.rs +++ b/wasm/vp_user/src/lib.rs @@ -218,6 +218,8 @@ mod tests { use address::testing::arb_non_internal_address; use namada_test_utils::TestWasms; + use namada_tests::governance; + use namada_tests::governance::parameters::GovernanceParameters; // Use this as `#[test]` annotation to enable logging use namada_tests::log::test; use namada_tests::native_vp::pos::init_pos; @@ -228,7 +230,9 @@ mod tests { use namada_tests::vp::vp_host_env::storage::Key; use namada_tests::vp::*; use namada_tx_prelude::dec::Dec; - use namada_tx_prelude::proof_of_stake::parameters::PosParams; + use namada_tx_prelude::proof_of_stake::parameters::{ + OwnedPosParams, PosParams, + }; use namada_tx_prelude::proof_of_stake::types::GenesisValidator; use namada_tx_prelude::storage::Epoch; use namada_tx_prelude::{StorageWrite, TxEnv}; @@ -470,7 +474,7 @@ mod tests { #[test] fn test_unsigned_non_validator_pos_action_rejected() { // Init PoS genesis - let pos_params = PosParams::default(); + let pos_params = OwnedPosParams::default(); let validator = address::testing::established_address_3(); let initial_stake = token::Amount::from_uint(10_098_123, 0).unwrap(); let consensus_key = key::testing::keypair_2().ref_to(); @@ -561,8 +565,14 @@ mod tests { #[test] fn test_unjail_with_demotion() { // Genesis validators - let mut pos_params = PosParams::default(); - pos_params.owned.max_validator_slots = 2; + let pos_params = PosParams { + owned: OwnedPosParams { + max_validator_slots: 2, + ..Default::default() + }, + max_proposal_period: GovernanceParameters::default() + .max_proposal_period, + }; // Common let protocol_key = key::testing::keypair_1().ref_to(); @@ -648,7 +658,8 @@ mod tests { .unwrap(); // Jail validator3 - jail_validator( + + jail_validator::<_, governance::Store<_>>( &mut tx_env.state, &pos_params, &validator3, @@ -708,7 +719,7 @@ mod tests { #[test] fn test_unsigned_become_validator_pos_action_rejected() { // Init PoS genesis - let pos_params = PosParams::default(); + let pos_params = OwnedPosParams::default(); let validator = address::testing::established_address_3(); let initial_stake = token::Amount::from_uint(10_098_123, 0).unwrap(); let consensus_key = key::testing::keypair_2().ref_to(); @@ -805,7 +816,7 @@ mod tests { #[test] fn test_unsigned_validator_pos_action_rejected() { // Init PoS genesis - let pos_params = PosParams::default(); + let pos_params = OwnedPosParams::default(); let validator = address::testing::established_address_3(); let initial_stake = token::Amount::from_uint(10_098_123, 0).unwrap(); let consensus_key = key::testing::keypair_2().ref_to(); @@ -908,7 +919,7 @@ mod tests { #[test] fn test_signed_non_validator_pos_action_accepted() { // Init PoS genesis - let pos_params = PosParams::default(); + let pos_params = OwnedPosParams::default(); let validator = address::testing::established_address_3(); let initial_stake = token::Amount::from_uint(10_098_123, 0).unwrap(); let consensus_key = key::testing::keypair_2().ref_to(); @@ -1003,7 +1014,7 @@ mod tests { #[test] fn test_signed_become_validator_pos_action_accepted() { // Init PoS genesis - let pos_params = PosParams::default(); + let pos_params = OwnedPosParams::default(); let validator = address::testing::established_address_3(); let initial_stake = token::Amount::from_uint(10_098_123, 0).unwrap(); let consensus_key = key::testing::keypair_2().ref_to(); @@ -1099,7 +1110,7 @@ mod tests { #[test] fn test_signed_validator_pos_action_accepted() { // Init PoS genesis - let pos_params = PosParams::default(); + let pos_params = OwnedPosParams::default(); let validator = address::testing::established_address_3(); let initial_stake = token::Amount::from_uint(10_098_123, 0).unwrap(); let consensus_key = key::testing::keypair_2().ref_to(); diff --git a/wasm_for_tests/Cargo.lock b/wasm_for_tests/Cargo.lock index 1e00f30b78d..1d928a1f8e9 100644 --- a/wasm_for_tests/Cargo.lock +++ b/wasm_for_tests/Cargo.lock @@ -3569,6 +3569,7 @@ dependencies = [ "namada_account", "namada_core", "namada_events", + "namada_governance", "namada_macros", "namada_parameters", "namada_proof_of_stake", @@ -3648,13 +3649,10 @@ dependencies = [ "namada_core", "namada_events", "namada_gas", - "namada_governance", "namada_macros", - "namada_parameters", "namada_state", "namada_storage", "namada_systems", - "namada_token", "namada_tx", "namada_vp", "primitive-types", @@ -3719,13 +3717,10 @@ dependencies = [ "namada_controller", "namada_core", "namada_events", - "namada_governance", "namada_macros", - "namada_parameters", "namada_state", "namada_storage", "namada_systems", - "namada_trans_token", "namada_tx", "namada_vp", "once_cell", diff --git a/wasm_for_tests/tx_proposal_code/src/lib.rs b/wasm_for_tests/tx_proposal_code/src/lib.rs index d05e8c32caf..3996e41fbec 100644 --- a/wasm_for_tests/tx_proposal_code/src/lib.rs +++ b/wasm_for_tests/tx_proposal_code/src/lib.rs @@ -39,7 +39,7 @@ fn apply_tx(ctx: &mut Ctx, _tx_data: BatchedTx) -> TxResult { ctx.write(&pgf_inflation_key, pgf_inflation_rate)?; // change pos parameter - let mut pos_params = read_pos_params(ctx)?.owned; + let mut pos_params = read_pos_params::<_, governance::Store<_>>(ctx)?.owned; pos_params.max_inflation_rate = Dec::from_str("0.15").unwrap(); pos_params.target_staked_ratio = Dec::from_str("0.33").unwrap(); pos_params.rewards_gain_p = Dec::from_str("1.5").unwrap();