Skip to content

Commit

Permalink
parameters: env agnostic VP
Browse files Browse the repository at this point in the history
  • Loading branch information
tzemanovic committed Sep 12, 2024
1 parent d32e856 commit 4fc3d95
Show file tree
Hide file tree
Showing 10 changed files with 70 additions and 120 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 10 additions & 9 deletions crates/benches/native_vps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ use namada_node::bench_utils::{
TX_BRIDGE_POOL_WASM, TX_IBC_WASM, TX_INIT_PROPOSAL_WASM, TX_RESIGN_STEWARD,
TX_TRANSFER_WASM, TX_UPDATE_STEWARD_COMMISSION, TX_VOTE_PROPOSAL_WASM,
};
use namada_vm::wasm::run::VpEvalWasm;
use namada_vp::native_vp::{Ctx, NativeVp};
use rand_core::OsRng;

Expand Down Expand Up @@ -1557,7 +1558,7 @@ fn parameters(c: &mut Criterion) {
let gas_meter = RefCell::new(VpGasMeter::new_from_tx_meter(
&TxGasMeter::new(u64::MAX),
));
let parameters = ParametersVp::new(Ctx::new(
let ctx = Ctx::<_, _, VpEvalWasm<_, _, _>>::new(
&vp_address,
&shell.state,
&signed_tx.tx,
Expand All @@ -1567,18 +1568,18 @@ fn parameters(c: &mut Criterion) {
&keys_changed,
&verifiers,
shell.vp_wasm_cache.clone(),
));
);

group.bench_function(bench_name, |b| {
b.iter(|| {
assert!(
parameters
.validate_tx(
&signed_tx.to_ref(),
parameters.ctx.keys_changed,
parameters.ctx.verifiers,
)
.is_ok()
ParametersVp::validate_tx(
&ctx,
&signed_tx.to_ref(),
ctx.keys_changed,
ctx.verifiers,
)
.is_ok()
)
})
});
Expand Down
15 changes: 7 additions & 8 deletions crates/node/src/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1238,14 +1238,13 @@ where
.map_err(Error::NativeVpError)
}
InternalAddress::Parameters => {
let parameters = ParametersVp::new(ctx);
parameters
.validate_tx(
batched_tx,
&keys_changed,
&verifiers,
)
.map_err(Error::NativeVpError)
ParametersVp::validate_tx(
&ctx,
batched_tx,
&keys_changed,
&verifiers,
)
.map_err(Error::NativeVpError)
}
InternalAddress::PosSlashPool => {
Err(Error::AccessForbidden(
Expand Down
15 changes: 9 additions & 6 deletions crates/node/src/shell/finalize_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1339,8 +1339,8 @@ mod test_finalize_block {
use namada_sdk::validation::ParametersVp;
use namada_test_utils::tx_data::TxWriteData;
use namada_test_utils::TestWasms;
use namada_vm::wasm::run::VpEvalWasm;
use namada_vote_ext::ethereum_events;
use namada_vp::native_vp::NativeVp;
use proof_of_stake::{bond_tokens, PosParams};
use test_log::test;

Expand Down Expand Up @@ -5650,7 +5650,7 @@ mod test_finalize_block {
let keys_changed = BTreeSet::from([min_confirmations_key()]);
let verifiers = BTreeSet::default();
let batched_tx = tx.batch_ref_first_tx().unwrap();
let ctx = namada_vp::native_vp::Ctx::new(
let ctx = namada_vp::native_vp::Ctx::<_, _, VpEvalWasm<_, _, _>>::new(
shell.mode.get_validator_address().expect("Test failed"),
shell.state.read_only(),
batched_tx.tx,
Expand All @@ -5661,11 +5661,14 @@ mod test_finalize_block {
&verifiers,
shell.vp_wasm_cache.clone(),
);
let parameters = ParametersVp::new(ctx);
assert!(
parameters
.validate_tx(&batched_tx, &keys_changed, &verifiers)
.is_ok()
ParametersVp::validate_tx(
&ctx,
&batched_tx,
&keys_changed,
&verifiers
)
.is_ok()
);

// we advance forward to the next epoch
Expand Down
2 changes: 1 addition & 1 deletion crates/parameters/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ namada_macros = { path = "../macros" }
namada_state = { path = "../state" }
namada_systems = { path = "../systems" }
namada_tx = { path = "../tx" }
namada_vp = { path = "../vp" }
namada_vp_env = { path = "../vp_env" }

smooth-operator.workspace = true
thiserror.workspace = true
Expand Down
57 changes: 16 additions & 41 deletions crates/parameters/src/vp.rs
Original file line number Diff line number Diff line change
@@ -1,40 +1,30 @@
//! Native VP for protocol parameters
//! VP for protocol parameters

use std::collections::BTreeSet;
use std::marker::PhantomData;

use namada_core::address::Address;
use namada_core::booleans::BoolResultUnitExt;
use namada_state::{Key, StateRead};
use namada_systems::governance;
use namada_tx::BatchedTxRef;
use namada_vp::native_vp::{
Ctx, CtxPreStorageRead, Error, NativeVp, Result, VpEvaluator,
};
use namada_vp_env::{Error, Key, Result, VpEnv};

use crate::storage;

/// Parameters VP
pub struct ParametersVp<'ctx, S, CA, EVAL, Gov>
where
S: 'static + StateRead,
{
/// Context to interact with the host structures.
pub ctx: Ctx<'ctx, S, CA, EVAL>,
/// Generic types for DI
pub _marker: PhantomData<Gov>,
pub struct ParametersVp<'ctx, CTX, Gov> {
/// Generic types for VP context and DI
pub _marker: PhantomData<(&'ctx CTX, Gov)>,
}

impl<'view, 'ctx: 'view, S, CA, EVAL, Gov> NativeVp<'view>
for ParametersVp<'ctx, S, CA, EVAL, Gov>
impl<'ctx, CTX, Gov> ParametersVp<'ctx, CTX, Gov>
where
S: 'static + StateRead,
CA: 'static + Clone,
EVAL: 'static + VpEvaluator<'ctx, S, CA, EVAL>,
Gov: governance::Read<CtxPreStorageRead<'view, 'ctx, S, CA, EVAL>>,
CTX: VpEnv<'ctx>,
Gov: governance::Read<<CTX as VpEnv<'ctx>>::Pre>,
{
fn validate_tx(
&'view self,
/// Run the validity predicate
pub fn validate_tx(
ctx: &'ctx CTX,
batched_tx: &BatchedTxRef<'_>,
keys_changed: &BTreeSet<Key>,
_verifiers: &BTreeSet<Address>,
Expand All @@ -45,43 +35,28 @@ where
data
} else {
return Err(Error::new_const(
"Token parameter changes require tx data to be present",
"Parameter changes require tx data to be present",
));
};
match key_type {
KeyType::PARAMETER | KeyType::UNKNOWN_PARAMETER => {
Gov::is_proposal_accepted(&self.ctx.pre(), &data)?
.ok_or_else(|| {
Gov::is_proposal_accepted(&ctx.pre(), &data)?.ok_or_else(
|| {
Error::new_alloc(format!(
"Attempted to change a protocol parameter \
from outside of a governance proposal, or \
from a non-accepted governance proposal: \
{key}",
))
})
},
)
}
KeyType::UNKNOWN => Ok(()),
}
})
}
}

impl<'ctx, S, CA, EVAL, Gov> ParametersVp<'ctx, S, CA, EVAL, Gov>
where
S: 'static + StateRead,
CA: 'static + Clone,
EVAL: 'static + VpEvaluator<'ctx, S, CA, EVAL>,
Gov: governance::Read<CtxPreStorageRead<'ctx, 'ctx, S, CA, EVAL>>,
{
/// Instantiate parameters VP
pub fn new(ctx: Ctx<'ctx, S, CA, EVAL>) -> Self {
Self {
ctx,
_marker: PhantomData,
}
}
}

#[allow(clippy::upper_case_acronyms)]
enum KeyType {
#[allow(clippy::upper_case_acronyms)]
Expand Down
10 changes: 4 additions & 6 deletions crates/sdk/src/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,10 @@ pub type IbcVpContext<'view, 'a, S, CA, EVAL> =
>;

/// Native parameters VP
pub type ParametersVp<'a, S, CA> = parameters::vp::ParametersVp<
'a,
S,
VpCache<CA>,
Eval<S, CA>,
GovPreStore<'a, S, CA>,
pub type ParametersVp<'ctx, CTX> = parameters::vp::ParametersVp<
'ctx,
CTX,
governance::Store<<CTX as namada_vp::VpEnv<'ctx>>::Pre>,
>;

/// Native governance VP
Expand Down
66 changes: 20 additions & 46 deletions crates/vp_env/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,9 @@ use namada_core::borsh::BorshDeserialize;
use namada_core::chain::ChainId;
pub use namada_core::chain::{BlockHeader, BlockHeight, Epoch, Epochs};
use namada_core::hash::Hash;
pub use namada_core::storage::{Key, TxIndex};
use namada_events::{Event, EventType};
use namada_gas::Gas;
pub use namada_storage::StorageRead;
pub use namada_storage::{Error, Key, Result, StorageRead, TxIndex};
use namada_tx::BatchedTxRef;

/// Validity predicate's environment is available for native VPs and WASM VPs
Expand Down Expand Up @@ -56,74 +55,61 @@ where
/// Storage read temporary state Borsh encoded value (after tx execution).
/// It will try to read from only the write log and then decode it if
/// found.
fn read_temp<T: BorshDeserialize>(
&self,
key: &Key,
) -> Result<Option<T>, namada_storage::Error>;
fn read_temp<T: BorshDeserialize>(&self, key: &Key) -> Result<Option<T>>;

/// Storage read temporary state raw bytes (after tx execution). It will try
/// to read from only the write log.
fn read_bytes_temp(
&self,
key: &Key,
) -> Result<Option<Vec<u8>>, namada_storage::Error>;
fn read_bytes_temp(&self, key: &Key) -> Result<Option<Vec<u8>>>;

/// Getting the chain ID.
fn get_chain_id(&self) -> Result<ChainId, namada_storage::Error>;
fn get_chain_id(&self) -> Result<ChainId>;

/// Getting the block height. The height is that of the block to which the
/// current transaction is being applied.
fn get_block_height(&self) -> Result<BlockHeight, namada_storage::Error>;
fn get_block_height(&self) -> Result<BlockHeight>;

/// Getting the block header.
fn get_block_header(
&self,
height: BlockHeight,
) -> Result<Option<BlockHeader>, namada_storage::Error>;
) -> Result<Option<BlockHeader>>;

/// Getting the block epoch. The epoch is that of the block to which the
/// current transaction is being applied.
fn get_block_epoch(&self) -> Result<Epoch, namada_storage::Error>;
fn get_block_epoch(&self) -> Result<Epoch>;

/// Get the shielded transaction index.
fn get_tx_index(&self) -> Result<TxIndex, namada_storage::Error>;
fn get_tx_index(&self) -> Result<TxIndex>;

/// Get the address of the native token.
fn get_native_token(&self) -> Result<Address, namada_storage::Error>;
fn get_native_token(&self) -> Result<Address>;

/// Given the information about predecessor block epochs
fn get_pred_epochs(&self) -> namada_storage::Result<Epochs>;

/// Get the events emitted by the current tx.
fn get_events(
&self,
event_type: &EventType,
) -> Result<Vec<Event>, namada_storage::Error>;
fn get_events(&self, event_type: &EventType) -> Result<Vec<Event>>;

/// Storage prefix iterator, ordered by storage keys. It will try to get an
/// iterator from the storage.
fn iter_prefix<'iter>(
&'iter self,
prefix: &Key,
) -> Result<Self::PrefixIter<'iter>, namada_storage::Error>;
) -> Result<Self::PrefixIter<'iter>>;

/// Evaluate a validity predicate with given data. The address, changed
/// storage keys and verifiers will have the same values as the input to
/// caller's validity predicate.
///
/// If the execution fails for whatever reason, this will return `false`.
/// Otherwise returns the result of evaluation.
fn eval(
&self,
vp_code: Hash,
input_data: BatchedTxRef<'_>,
) -> Result<(), namada_storage::Error>;
fn eval(&self, vp_code: Hash, input_data: BatchedTxRef<'_>) -> Result<()>;

/// Get a tx hash
fn get_tx_code_hash(&self) -> Result<Option<Hash>, namada_storage::Error>;
fn get_tx_code_hash(&self) -> Result<Option<Hash>>;

/// Charge the provided gas for the current vp
fn charge_gas(&self, used_gas: Gas) -> Result<(), namada_storage::Error>;
fn charge_gas(&self, used_gas: Gas) -> Result<()>;

// ---- Methods below have default implementation via `pre/post` ----

Expand All @@ -132,16 +118,13 @@ where
fn read_pre<T: BorshDeserialize>(
&'view self,
key: &Key,
) -> Result<Option<T>, namada_storage::Error> {
) -> Result<Option<T>> {
self.pre().read(key)
}

/// Storage read prior state raw bytes (before tx execution). It
/// will try to read from the storage.
fn read_bytes_pre(
&'view self,
key: &Key,
) -> Result<Option<Vec<u8>>, namada_storage::Error> {
fn read_bytes_pre(&'view self, key: &Key) -> Result<Option<Vec<u8>>> {
self.pre().read_bytes(key)
}

Expand All @@ -151,35 +134,26 @@ where
fn read_post<T: BorshDeserialize>(
&'view self,
key: &Key,
) -> Result<Option<T>, namada_storage::Error> {
) -> Result<Option<T>> {
self.post().read(key)
}

/// Storage read posterior state raw bytes (after tx execution). It will try
/// to read from the write log first and if no entry found then from the
/// storage.
fn read_bytes_post(
&'view self,
key: &Key,
) -> Result<Option<Vec<u8>>, namada_storage::Error> {
fn read_bytes_post(&'view self, key: &Key) -> Result<Option<Vec<u8>>> {
self.post().read_bytes(key)
}

/// Storage `has_key` in prior state (before tx execution). It will try to
/// read from the storage.
fn has_key_pre(
&'view self,
key: &Key,
) -> Result<bool, namada_storage::Error> {
fn has_key_pre(&'view self, key: &Key) -> Result<bool> {
self.pre().has_key(key)
}

/// Storage `has_key` in posterior state (after tx execution). It will try
/// to check the write log first and if no entry found then the storage.
fn has_key_post(
&'view self,
key: &Key,
) -> Result<bool, namada_storage::Error> {
fn has_key_post(&'view self, key: &Key) -> Result<bool> {
self.post().has_key(key)
}
}
Loading

0 comments on commit 4fc3d95

Please sign in to comment.