Skip to content

Commit

Permalink
shared: Add pre/post to VpEnv and use them to provide default impls
Browse files Browse the repository at this point in the history
  • Loading branch information
tzemanovic committed Aug 24, 2022
1 parent ff268e1 commit 70f9982
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 227 deletions.
119 changes: 7 additions & 112 deletions shared/src/ledger/native_vp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,63 +270,23 @@ where
}
}

impl<'a, DB, H, CA> VpEnv for Ctx<'a, DB, H, CA>
impl<'view, 'a: 'view, DB, H, CA> VpEnv<'view> for Ctx<'a, DB, H, CA>
where
DB: 'static + storage::DB + for<'iter> storage::DBIter<'iter>,
H: 'static + StorageHasher,
CA: 'static + WasmCacheAccess,
{
type Error = Error;
type Post = CtxPostStorageRead<'view, 'a, DB, H, CA>;
type Pre = CtxPreStorageRead<'view, 'a, DB, H, CA>;
type PrefixIter = <DB as storage::DBIter<'a>>::PrefixIter;

fn read_pre<T: borsh::BorshDeserialize>(
&self,
key: &Key,
) -> Result<Option<T>, Self::Error> {
vp_env::read_pre(
&mut *self.gas_meter.borrow_mut(),
self.storage,
self.write_log,
key,
)
.map(|data| data.and_then(|t| T::try_from_slice(&t[..]).ok()))
}

fn read_bytes_pre(
&self,
key: &Key,
) -> Result<Option<Vec<u8>>, Self::Error> {
vp_env::read_pre(
&mut *self.gas_meter.borrow_mut(),
self.storage,
self.write_log,
key,
)
}

fn read_post<T: borsh::BorshDeserialize>(
&self,
key: &Key,
) -> Result<Option<T>, Self::Error> {
vp_env::read_post(
&mut *self.gas_meter.borrow_mut(),
self.storage,
self.write_log,
key,
)
.map(|data| data.and_then(|t| T::try_from_slice(&t[..]).ok()))
fn pre(&'view self) -> Self::Pre {
CtxPreStorageRead { ctx: self }
}

fn read_bytes_post(
&self,
key: &Key,
) -> Result<Option<Vec<u8>>, Self::Error> {
vp_env::read_post(
&mut *self.gas_meter.borrow_mut(),
self.storage,
self.write_log,
key,
)
fn post(&'view self) -> Self::Post {
CtxPostStorageRead { ctx: self }
}

fn read_temp<T: borsh::BorshDeserialize>(
Expand All @@ -352,71 +312,6 @@ where
)
}

fn has_key_pre(&self, key: &Key) -> Result<bool, Self::Error> {
vp_env::has_key_pre(
&mut *self.gas_meter.borrow_mut(),
self.storage,
key,
)
}

fn has_key_post(&self, key: &Key) -> Result<bool, Self::Error> {
vp_env::has_key_post(
&mut *self.gas_meter.borrow_mut(),
self.storage,
self.write_log,
key,
)
}

fn get_chain_id(&self) -> Result<String, Self::Error> {
vp_env::get_chain_id(&mut *self.gas_meter.borrow_mut(), self.storage)
}

fn get_block_height(&self) -> Result<BlockHeight, Self::Error> {
vp_env::get_block_height(
&mut *self.gas_meter.borrow_mut(),
self.storage,
)
}

fn get_block_hash(&self) -> Result<BlockHash, Self::Error> {
vp_env::get_block_hash(&mut *self.gas_meter.borrow_mut(), self.storage)
}

fn get_block_epoch(&self) -> Result<Epoch, Self::Error> {
vp_env::get_block_epoch(&mut *self.gas_meter.borrow_mut(), self.storage)
}

fn iter_prefix(
&self,
prefix: &Key,
) -> Result<Self::PrefixIter, Self::Error> {
vp_env::iter_prefix(
&mut *self.gas_meter.borrow_mut(),
self.storage,
prefix,
)
}

fn iter_pre_next(
&self,
iter: &mut Self::PrefixIter,
) -> Result<Option<(String, Vec<u8>)>, Self::Error> {
vp_env::iter_pre_next::<DB>(&mut *self.gas_meter.borrow_mut(), iter)
}

fn iter_post_next(
&self,
iter: &mut Self::PrefixIter,
) -> Result<Option<(String, Vec<u8>)>, Self::Error> {
vp_env::iter_post_next::<DB>(
&mut *self.gas_meter.borrow_mut(),
self.write_log,
iter,
)
}

fn eval(
&self,
vp_code: Vec<u8>,
Expand Down
170 changes: 105 additions & 65 deletions shared/src/ledger/vp_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use borsh::BorshDeserialize;
use thiserror::Error;

use super::gas::MIN_STORAGE_GAS;
use super::storage_api;
use super::storage_api::{self, StorageRead};
use crate::ledger::gas;
use crate::ledger::gas::VpGasMeter;
use crate::ledger::storage::write_log::WriteLog;
Expand All @@ -18,124 +18,164 @@ use crate::types::key::common;
use crate::types::storage::{BlockHash, BlockHeight, Epoch, Key};

/// Validity predicate's environment is available for native VPs and WASM VPs
pub trait VpEnv {
pub trait VpEnv<'view> {
/// Storage read prefix iterator
type PrefixIter;

/// Host functions possible errors, extensible with custom user errors.
type Error;
type Error: From<storage_api::Error>;

/// Storage read prior state Borsh encoded value (before tx execution). It
/// will try to read from the storage and decode it if found.
fn read_pre<T: BorshDeserialize>(
&self,
key: &Key,
) -> Result<Option<T>, Self::Error>;
/// Type to read storage state before the transaction execution
type Pre: StorageRead<PrefixIter = Self::PrefixIter>;

/// Storage read prior state raw bytes (before tx execution). It
/// will try to read from the storage.
fn read_bytes_pre(&self, key: &Key)
-> Result<Option<Vec<u8>>, Self::Error>;
/// Type to read storage state after the transaction execution
type Post: StorageRead<PrefixIter = Self::PrefixIter>;

/// Storage read posterior state Borsh encoded value (after tx execution).
/// It will try to read from the write log first and if no entry found
/// then from the storage and then decode it if found.
fn read_post<T: BorshDeserialize>(
&self,
key: &Key,
) -> Result<Option<T>, Self::Error>;
/// Read storage state before the transaction execution
fn pre(&'view self) -> Self::Pre;

/// 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(
&self,
key: &Key,
) -> Result<Option<Vec<u8>>, Self::Error>;
/// Read storage state after the transaction execution
fn post(&'view self) -> Self::Post;

/// 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,
&'view self,
key: &Key,
) -> Result<Option<T>, Self::Error>;

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

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

/// 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(&self, key: &Key) -> Result<bool, Self::Error>;
fn has_key_post(&'view self, key: &Key) -> Result<bool, Self::Error> {
self.post().has_key(key).map_err(Into::into)
}

/// 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(
&'view self,
vp_code: Vec<u8>,
input_data: Vec<u8>,
) -> Result<bool, Self::Error>;

/// Verify a transaction signature. The signature is expected to have been
/// produced on the encoded transaction [`crate::proto::Tx`]
/// using [`crate::proto::Tx::sign`].
fn verify_tx_signature(
&'view self,
pk: &common::PublicKey,
sig: &common::Signature,
) -> Result<bool, Self::Error>;

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

/// Storage read prior state Borsh encoded value (before tx execution). It
/// will try to read from the storage and decode it if found.
fn read_pre<T: BorshDeserialize>(
&'view self,
key: &Key,
) -> Result<Option<T>, Self::Error> {
self.pre().read(key).map_err(Into::into)
}

/// 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>>, Self::Error> {
self.pre().read_bytes(key).map_err(Into::into)
}

/// Storage read posterior state Borsh encoded value (after tx execution).
/// It will try to read from the write log first and if no entry found
/// then from the storage and then decode it if found.
fn read_post<T: BorshDeserialize>(
&'view self,
key: &Key,
) -> Result<Option<T>, Self::Error> {
self.post().read(key).map_err(Into::into)
}

/// 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>>, Self::Error> {
self.post().read_bytes(key).map_err(Into::into)
}

/// Getting the chain ID.
fn get_chain_id(&self) -> Result<String, Self::Error>;
fn get_chain_id(&'view self) -> Result<String, Self::Error> {
self.pre().get_chain_id().map_err(Into::into)
}

/// 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, Self::Error>;
fn get_block_height(&'view self) -> Result<BlockHeight, Self::Error> {
self.pre().get_block_height().map_err(Into::into)
}

/// Getting the block hash. The height is that of the block to which the
/// current transaction is being applied.
fn get_block_hash(&self) -> Result<BlockHash, Self::Error>;
fn get_block_hash(&'view self) -> Result<BlockHash, Self::Error> {
self.pre().get_block_hash().map_err(Into::into)
}

/// 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, Self::Error>;
fn get_block_epoch(&'view self) -> Result<Epoch, Self::Error> {
self.pre().get_block_epoch().map_err(Into::into)
}

/// Storage prefix iterator. It will try to get an iterator from the
/// storage.
fn iter_prefix(
&self,
&'view self,
prefix: &Key,
) -> Result<Self::PrefixIter, Self::Error>;
) -> Result<Self::PrefixIter, Self::Error> {
self.pre().iter_prefix(prefix).map_err(Into::into)
}

/// Storage prefix iterator for prior state (before tx execution). It will
/// try to read from the storage.
fn iter_pre_next(
&self,
&'view self,
iter: &mut Self::PrefixIter,
) -> Result<Option<(String, Vec<u8>)>, Self::Error>;
) -> Result<Option<(String, Vec<u8>)>, Self::Error> {
self.pre().iter_next(iter).map_err(Into::into)
}

/// Storage prefix iterator next for posterior state (after tx execution).
/// It will try to read from the write log first and if no entry found
/// then from the storage.
fn iter_post_next(
&self,
&'view self,
iter: &mut Self::PrefixIter,
) -> Result<Option<(String, Vec<u8>)>, Self::Error>;

/// 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: Vec<u8>,
input_data: Vec<u8>,
) -> Result<bool, Self::Error>;

/// Verify a transaction signature. The signature is expected to have been
/// produced on the encoded transaction [`crate::proto::Tx`]
/// using [`crate::proto::Tx::sign`].
fn verify_tx_signature(
&self,
pk: &common::PublicKey,
sig: &common::Signature,
) -> Result<bool, Self::Error>;

/// Get a tx hash
fn get_tx_code_hash(&self) -> Result<Hash, Self::Error>;
) -> Result<Option<(String, Vec<u8>)>, Self::Error> {
self.pre().iter_next(iter).map_err(Into::into)
}
}

/// These runtime errors will abort VP execution immediately
Expand Down
Loading

0 comments on commit 70f9982

Please sign in to comment.