From 4422d8c36e22dcd555c348a636bc406988ea87c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Thu, 25 Aug 2022 10:30:32 +0200 Subject: [PATCH] shared: Add pre/post to VpEnv and use them to provide default impls --- shared/src/ledger/native_vp.rs | 180 +++++++++++---------------- shared/src/ledger/storage_api/mod.rs | 8 +- shared/src/ledger/vp_env.rs | 142 +++++++++++++-------- vp_prelude/src/lib.rs | 122 ++++++------------ 4 files changed, 205 insertions(+), 247 deletions(-) diff --git a/shared/src/ledger/native_vp.rs b/shared/src/ledger/native_vp.rs index fa30efb7eae..97e99215b24 100644 --- a/shared/src/ledger/native_vp.rs +++ b/shared/src/ledger/native_vp.rs @@ -162,23 +162,52 @@ where &self, key: &crate::types::storage::Key, ) -> Result, storage_api::Error> { - self.ctx.read_pre(key).into_storage_result() + vp_env::read_pre( + &mut *self.ctx.gas_meter.borrow_mut(), + self.ctx.storage, + self.ctx.write_log, + key, + ) + .map(|data| data.and_then(|t| T::try_from_slice(&t[..]).ok())) + .into_storage_result() } fn read_bytes( &self, key: &crate::types::storage::Key, ) -> Result>, storage_api::Error> { - self.ctx.read_bytes_pre(key).into_storage_result() + vp_env::read_pre( + &mut *self.ctx.gas_meter.borrow_mut(), + self.ctx.storage, + self.ctx.write_log, + key, + ) + .into_storage_result() } fn has_key( &self, key: &crate::types::storage::Key, ) -> Result { - self.ctx.has_key_pre(key).into_storage_result() + vp_env::has_key_pre( + &mut *self.ctx.gas_meter.borrow_mut(), + self.ctx.storage, + key, + ) + .into_storage_result() + } + + fn iter_next( + &self, + iter: &mut Self::PrefixIter, + ) -> Result)>, storage_api::Error> { + vp_env::iter_pre_next::(&mut *self.ctx.gas_meter.borrow_mut(), iter) + .into_storage_result() } + // ---- Methods below are implemented in `self.ctx`, because they are + // the same in `pre/post` ---- + fn iter_prefix( &self, prefix: &crate::types::storage::Key, @@ -186,13 +215,6 @@ where self.ctx.iter_prefix(prefix).into_storage_result() } - fn iter_next( - &self, - iter: &mut Self::PrefixIter, - ) -> Result)>, storage_api::Error> { - self.ctx.iter_pre_next(iter).into_storage_result() - } - fn get_chain_id(&self) -> Result { self.ctx.get_chain_id().into_storage_result() } @@ -222,14 +244,27 @@ where &self, key: &crate::types::storage::Key, ) -> Result, storage_api::Error> { - self.ctx.read_post(key).into_storage_result() + vp_env::read_post( + &mut *self.ctx.gas_meter.borrow_mut(), + self.ctx.storage, + self.ctx.write_log, + key, + ) + .map(|data| data.and_then(|t| T::try_from_slice(&t[..]).ok())) + .into_storage_result() } fn read_bytes( &self, key: &crate::types::storage::Key, ) -> Result>, storage_api::Error> { - self.ctx.read_bytes_post(key).into_storage_result() + vp_env::read_post( + &mut *self.ctx.gas_meter.borrow_mut(), + self.ctx.storage, + self.ctx.write_log, + key, + ) + .into_storage_result() } fn has_key( @@ -239,6 +274,21 @@ where self.ctx.has_key_post(key).into_storage_result() } + fn iter_next( + &self, + iter: &mut Self::PrefixIter, + ) -> Result)>, storage_api::Error> { + vp_env::iter_post_next::( + &mut *self.ctx.gas_meter.borrow_mut(), + self.ctx.write_log, + iter, + ) + .into_storage_result() + } + + // ---- Methods below are implemented in `self.ctx`, because they are + // the same in `pre/post` ---- + fn iter_prefix( &self, prefix: &crate::types::storage::Key, @@ -246,13 +296,6 @@ where self.ctx.iter_prefix(prefix).into_storage_result() } - fn iter_next( - &self, - iter: &mut Self::PrefixIter, - ) -> Result)>, storage_api::Error> { - self.ctx.iter_post_next(iter).into_storage_result() - } - fn get_chain_id(&self) -> Result { self.ctx.get_chain_id().into_storage_result() } @@ -270,63 +313,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 = >::PrefixIter; - fn read_pre( - &self, - key: &Key, - ) -> Result, 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>, Self::Error> { - vp_env::read_pre( - &mut *self.gas_meter.borrow_mut(), - self.storage, - self.write_log, - key, - ) - } - - fn read_post( - &self, - key: &Key, - ) -> Result, 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>, 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( @@ -352,44 +355,27 @@ where ) } - fn has_key_pre(&self, key: &Key) -> Result { - vp_env::has_key_pre( - &mut *self.gas_meter.borrow_mut(), - self.storage, - key, - ) - } - - fn has_key_post(&self, key: &Key) -> Result { - vp_env::has_key_post( - &mut *self.gas_meter.borrow_mut(), - self.storage, - self.write_log, - key, - ) - } - - fn get_chain_id(&self) -> Result { + fn get_chain_id(&'view self) -> Result { vp_env::get_chain_id(&mut *self.gas_meter.borrow_mut(), self.storage) } - fn get_block_height(&self) -> Result { + fn get_block_height(&'view self) -> Result { vp_env::get_block_height( &mut *self.gas_meter.borrow_mut(), self.storage, ) } - fn get_block_hash(&self) -> Result { + fn get_block_hash(&'view self) -> Result { vp_env::get_block_hash(&mut *self.gas_meter.borrow_mut(), self.storage) } - fn get_block_epoch(&self) -> Result { + fn get_block_epoch(&'view self) -> Result { vp_env::get_block_epoch(&mut *self.gas_meter.borrow_mut(), self.storage) } fn iter_prefix( - &self, + &'view self, prefix: &Key, ) -> Result { vp_env::iter_prefix( @@ -399,24 +385,6 @@ where ) } - fn iter_pre_next( - &self, - iter: &mut Self::PrefixIter, - ) -> Result)>, Self::Error> { - vp_env::iter_pre_next::(&mut *self.gas_meter.borrow_mut(), iter) - } - - fn iter_post_next( - &self, - iter: &mut Self::PrefixIter, - ) -> Result)>, Self::Error> { - vp_env::iter_post_next::( - &mut *self.gas_meter.borrow_mut(), - self.write_log, - iter, - ) - } - fn eval( &self, vp_code: Vec, diff --git a/shared/src/ledger/storage_api/mod.rs b/shared/src/ledger/storage_api/mod.rs index 0c0e4f4083a..b7f704d383d 100644 --- a/shared/src/ledger/storage_api/mod.rs +++ b/shared/src/ledger/storage_api/mod.rs @@ -26,16 +26,16 @@ pub trait StorageRead { /// Storage `has_key` in. It will try to read from the storage. fn has_key(&self, key: &storage::Key) -> Result; - /// Storage prefix iterator. It will try to get an iterator from the - /// storage. - fn iter_prefix(&self, prefix: &storage::Key) -> Result; - /// Storage prefix iterator for. It will try to read from the storage. fn iter_next( &self, iter: &mut Self::PrefixIter, ) -> Result)>>; + /// Storage prefix iterator. It will try to get an iterator from the + /// storage. + fn iter_prefix(&self, prefix: &storage::Key) -> Result; + /// Getting the chain ID. fn get_chain_id(&self) -> Result; diff --git a/shared/src/ledger/vp_env.rs b/shared/src/ledger/vp_env.rs index 95e7c48782f..51f20f78e22 100644 --- a/shared/src/ledger/vp_env.rs +++ b/shared/src/ledger/vp_env.rs @@ -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; @@ -18,40 +18,24 @@ 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 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( - &self, - key: &Key, - ) -> Result, Self::Error>; + /// Type to read storage state before the transaction execution + type Pre: StorageRead; - /// 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>, Self::Error>; + /// Type to read storage state after the transaction execution + type Post: StorageRead; - /// 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( - &self, - key: &Key, - ) -> Result, 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>, 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 @@ -68,51 +52,28 @@ pub trait VpEnv { key: &Key, ) -> Result>, 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; - - /// 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; - /// Getting the chain ID. - fn get_chain_id(&self) -> Result; + fn get_chain_id(&'view self) -> Result; /// 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; + fn get_block_height(&'view self) -> Result; /// 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; + fn get_block_hash(&'view self) -> Result; /// 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; + fn get_block_epoch(&'view self) -> Result; /// Storage prefix iterator. It will try to get an iterator from the /// storage. fn iter_prefix( - &self, + &'view self, prefix: &Key, ) -> Result; - /// Storage prefix iterator for prior state (before tx execution). It will - /// try to read from the storage. - fn iter_pre_next( - &self, - iter: &mut Self::PrefixIter, - ) -> Result)>, Self::Error>; - - /// 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, - iter: &mut Self::PrefixIter, - ) -> Result)>, 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. @@ -136,6 +97,77 @@ pub trait VpEnv { /// Get a tx hash fn get_tx_code_hash(&self) -> Result; + + // ---- Methods below have default implementation via `pre/post` ---- + + /// 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( + &'view self, + key: &Key, + ) -> Result, 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>, 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( + &'view self, + key: &Key, + ) -> Result, 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>, Self::Error> { + self.post().read_bytes(key).map_err(Into::into) + } + + /// 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 { + 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(&'view self, key: &Key) -> Result { + self.post().has_key(key).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( + &'view self, + iter: &mut Self::PrefixIter, + ) -> Result)>, 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( + &'view self, + iter: &mut Self::PrefixIter, + ) -> Result)>, Self::Error> { + self.pre().iter_next(iter).map_err(Into::into) + } } /// These runtime errors will abort VP execution immediately diff --git a/vp_prelude/src/lib.rs b/vp_prelude/src/lib.rs index 37d1958aa99..8afa9fca22a 100644 --- a/vp_prelude/src/lib.rs +++ b/vp_prelude/src/lib.rs @@ -150,36 +150,18 @@ pub fn reject() -> VpResult { #[derive(Debug)] pub struct KeyValIterator(pub u64, pub PhantomData); -impl VpEnv for Ctx { +impl<'view> VpEnv<'view> for Ctx { type Error = Error; + type Post = CtxPostStorageRead<'view>; + type Pre = CtxPreStorageRead<'view>; type PrefixIter = KeyValIterator<(String, Vec)>; - fn read_pre( - &self, - key: &storage::Key, - ) -> Result, Self::Error> { - self.pre().read(key).into_env_result() - } - - fn read_bytes_pre( - &self, - key: &storage::Key, - ) -> Result>, Self::Error> { - self.pre().read_bytes(key).into_env_result() - } - - fn read_post( - &self, - key: &storage::Key, - ) -> Result, Self::Error> { - self.post().read(key).into_env_result() + fn pre(&'view self) -> Self::Pre { + CtxPreStorageRead { _ctx: self } } - fn read_bytes_post( - &self, - key: &storage::Key, - ) -> Result>, Self::Error> { - self.post().read_bytes(key).into_env_result() + fn post(&'view self) -> Self::Post { + CtxPostStorageRead { _ctx: self } } fn read_temp( @@ -203,29 +185,24 @@ impl VpEnv for Ctx { Ok(read_from_buffer(read_result, anoma_vp_result_buffer)) } - fn has_key_pre(&self, key: &storage::Key) -> Result { - self.pre().has_key(key).into_env_result() - } - - fn has_key_post(&self, key: &storage::Key) -> Result { - self.post().has_key(key).into_env_result() - } - - fn get_chain_id(&self) -> Result { + fn get_chain_id(&'view self) -> Result { // Both `CtxPreStorageRead` and `CtxPostStorageRead` have the same impl - self.pre().get_chain_id().into_env_result() + get_chain_id().into_env_result() } - fn get_block_height(&self) -> Result { - self.pre().get_block_height().into_env_result() + fn get_block_height(&'view self) -> Result { + // Both `CtxPreStorageRead` and `CtxPostStorageRead` have the same impl + get_block_height().into_env_result() } - fn get_block_hash(&self) -> Result { - self.pre().get_block_hash().into_env_result() + fn get_block_hash(&'view self) -> Result { + // Both `CtxPreStorageRead` and `CtxPostStorageRead` have the same impl + get_block_hash().into_env_result() } - fn get_block_epoch(&self) -> Result { - self.pre().get_block_epoch().into_env_result() + fn get_block_epoch(&'view self) -> Result { + // Both `CtxPreStorageRead` and `CtxPostStorageRead` have the same impl + get_block_epoch().into_env_result() } fn iter_prefix( @@ -233,21 +210,7 @@ impl VpEnv for Ctx { prefix: &storage::Key, ) -> Result { // Both `CtxPreStorageRead` and `CtxPostStorageRead` have the same impl - self.pre().iter_prefix(prefix).into_env_result() - } - - fn iter_pre_next( - &self, - iter: &mut Self::PrefixIter, - ) -> Result)>, Self::Error> { - self.pre().iter_next(iter).into_env_result() - } - - fn iter_post_next( - &self, - iter: &mut Self::PrefixIter, - ) -> Result)>, Self::Error> { - self.post().iter_next(iter).into_env_result() + iter_prefix(prefix).into_env_result() } fn eval( @@ -329,14 +292,6 @@ impl StorageRead for CtxPreStorageRead<'_> { Ok(HostEnvResult::is_success(found)) } - fn iter_prefix( - &self, - prefix: &storage::Key, - ) -> Result { - // Note that this is the same as `CtxPostStorageRead` - iter_prefix(prefix) - } - fn iter_next( &self, iter: &mut Self::PrefixIter, @@ -348,27 +303,29 @@ impl StorageRead for CtxPreStorageRead<'_> { )) } + // ---- Methods below share the same implementation in `pre/post` ---- + + fn iter_prefix( + &self, + prefix: &storage::Key, + ) -> Result { + iter_prefix(prefix) + } + fn get_chain_id(&self) -> Result { get_chain_id() } fn get_block_height(&self) -> Result { - Ok(BlockHeight(unsafe { anoma_vp_get_block_height() })) + get_block_height() } fn get_block_hash(&self) -> Result { - let result = Vec::with_capacity(BLOCK_HASH_LENGTH); - unsafe { - anoma_vp_get_block_hash(result.as_ptr() as _); - } - let slice = unsafe { - slice::from_raw_parts(result.as_ptr(), BLOCK_HASH_LENGTH) - }; - Ok(BlockHash::try_from(slice).expect("Cannot convert the hash")) + get_block_hash() } fn get_block_epoch(&self) -> Result { - Ok(Epoch(unsafe { anoma_vp_get_block_epoch() })) + get_block_epoch() } } @@ -406,14 +363,6 @@ impl StorageRead for CtxPostStorageRead<'_> { Ok(HostEnvResult::is_success(found)) } - fn iter_prefix( - &self, - prefix: &storage::Key, - ) -> Result { - // Note that this is the same as `CtxPreStorageRead` - iter_prefix(prefix) - } - fn iter_next( &self, iter: &mut Self::PrefixIter, @@ -425,6 +374,15 @@ impl StorageRead for CtxPostStorageRead<'_> { )) } + // ---- Methods below share the same implementation in `pre/post` ---- + + fn iter_prefix( + &self, + prefix: &storage::Key, + ) -> Result { + iter_prefix(prefix) + } + fn get_chain_id(&self) -> Result { get_chain_id() }