Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add temp wl storage #1051

Merged
merged 2 commits into from
Apr 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/unreleased/improvements/1051-temp-wl-storage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- Added a TempWlStorage for storage_api::StorageRead/Write
in ABCI++ prepare/process proposal handler.
([#1051](https://github.com/anoma/namada/pull/1051))
4 changes: 2 additions & 2 deletions core/src/ledger/storage/masp_conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ pub fn update_allowed_conversions<D, H>(
wl_storage: &mut super::WlStorage<D, H>,
) -> crate::ledger::storage_api::Result<()>
where
D: super::DB + for<'iter> super::DBIter<'iter>,
H: super::StorageHasher,
D: 'static + super::DB + for<'iter> super::DBIter<'iter>,
H: 'static + super::StorageHasher,
{
use masp_primitives::ff::PrimeField;
use masp_primitives::transaction::components::Amount as MaspAmount;
Expand Down
2 changes: 1 addition & 1 deletion core/src/ledger/storage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub use merkle_tree::{
use thiserror::Error;
pub use traits::{Sha256Hasher, StorageHasher};
pub use wl_storage::{
iter_prefix_post, iter_prefix_pre, PrefixIter, WlStorage,
iter_prefix_post, iter_prefix_pre, PrefixIter, TempWlStorage, WlStorage,
};

#[cfg(feature = "wasm-runtime")]
Expand Down
138 changes: 120 additions & 18 deletions core/src/ledger/storage/wl_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,97 @@ where
pub storage: Storage<D, H>,
}

/// Temporary storage that can be used for changes that will never be committed
/// to the DB. This is useful for the shell `PrepareProposal` and
/// `ProcessProposal` handlers that should not change state, but need to apply
/// storage changes for replay protection to validate the proposal.
#[derive(Debug)]
pub struct TempWlStorage<'a, D, H>
where
D: DB + for<'iter> DBIter<'iter>,
H: StorageHasher,
{
/// Write log
pub write_log: WriteLog,
/// Storage provides access to DB
pub storage: &'a Storage<D, H>,
}

impl<'a, D, H> TempWlStorage<'a, D, H>
where
D: DB + for<'iter> DBIter<'iter>,
H: StorageHasher,
{
/// Create a temp storage that can mutated in memory, but never committed to
/// DB.
pub fn new(storage: &'a Storage<D, H>) -> Self {
Self {
write_log: WriteLog::default(),
storage,
}
}
}

/// Common trait for [`WlStorage`] and [`TempWlStorage`], used to implement
/// storage_api traits.
trait WriteLogAndStorage {
// DB type
type D: DB + for<'iter> DBIter<'iter>;
// DB hasher type
type H: StorageHasher;

/// Borrow `WriteLog`
fn write_log(&self) -> &WriteLog;

/// Borrow mutable `WriteLog`
fn write_log_mut(&mut self) -> &mut WriteLog;

/// Borrow `Storage`
fn storage(&self) -> &Storage<Self::D, Self::H>;
}

impl<D, H> WriteLogAndStorage for WlStorage<D, H>
where
D: DB + for<'iter> DBIter<'iter>,
H: StorageHasher,
{
type D = D;
type H = H;

fn write_log(&self) -> &WriteLog {
&self.write_log
}

fn write_log_mut(&mut self) -> &mut WriteLog {
&mut self.write_log
}

fn storage(&self) -> &Storage<D, H> {
&self.storage
}
}

impl<D, H> WriteLogAndStorage for TempWlStorage<'_, D, H>
where
D: DB + for<'iter> DBIter<'iter>,
H: StorageHasher,
{
type D = D;
type H = H;

fn write_log(&self) -> &WriteLog {
&self.write_log
}

fn write_log_mut(&mut self) -> &mut WriteLog {
&mut self.write_log
}

fn storage(&self) -> &Storage<D, H> {
self.storage
}
}

impl<D, H> WlStorage<D, H>
where
D: 'static + DB + for<'iter> DBIter<'iter>,
Expand Down Expand Up @@ -204,10 +295,11 @@ where
}
}

impl<D, H> StorageRead for WlStorage<D, H>
impl<T, D, H> StorageRead for T
where
D: DB + for<'iter> DBIter<'iter>,
H: StorageHasher,
T: WriteLogAndStorage<D = D, H = H>,
D: 'static + DB + for<'iter> DBIter<'iter>,
H: 'static + StorageHasher,
{
type PrefixIter<'iter> = PrefixIter<'iter, D> where Self: 'iter;

Expand All @@ -216,7 +308,7 @@ where
key: &storage::Key,
) -> storage_api::Result<Option<Vec<u8>>> {
// try to read from the write log first
let (log_val, _gas) = self.write_log.read(key);
let (log_val, _gas) = self.write_log().read(key);
match log_val {
Some(&write_log::StorageModification::Write { ref value }) => {
Ok(Some(value.clone()))
Expand All @@ -231,14 +323,17 @@ where
}
None => {
// when not found in write log, try to read from the storage
self.storage.db.read_subspace_val(key).into_storage_result()
self.storage()
.db
.read_subspace_val(key)
.into_storage_result()
}
}
}

fn has_key(&self, key: &storage::Key) -> storage_api::Result<bool> {
// try to read from the write log first
let (log_val, _gas) = self.write_log.read(key);
let (log_val, _gas) = self.write_log().read(key);
match log_val {
Some(&write_log::StorageModification::Write { .. })
| Some(&write_log::StorageModification::InitAccount { .. })
Expand All @@ -249,7 +344,7 @@ where
}
None => {
// when not found in write log, try to check the storage
self.storage.block.tree.has_key(key).into_storage_result()
self.storage().block.tree.has_key(key).into_storage_result()
}
}
}
Expand All @@ -259,7 +354,7 @@ where
prefix: &storage::Key,
) -> storage_api::Result<Self::PrefixIter<'iter>> {
let (iter, _gas) =
iter_prefix_post(&self.write_log, &self.storage, prefix);
iter_prefix_post(self.write_log(), self.storage(), prefix);
Ok(iter)
}

Expand All @@ -271,40 +366,41 @@ where
}

fn get_chain_id(&self) -> std::result::Result<String, storage_api::Error> {
Ok(self.storage.chain_id.to_string())
Ok(self.storage().chain_id.to_string())
}

fn get_block_height(
&self,
) -> std::result::Result<storage::BlockHeight, storage_api::Error> {
Ok(self.storage.block.height)
Ok(self.storage().block.height)
}

fn get_block_hash(
&self,
) -> std::result::Result<storage::BlockHash, storage_api::Error> {
Ok(self.storage.block.hash.clone())
Ok(self.storage().block.hash.clone())
}

fn get_block_epoch(
&self,
) -> std::result::Result<storage::Epoch, storage_api::Error> {
Ok(self.storage.block.epoch)
Ok(self.storage().block.epoch)
}

fn get_tx_index(
&self,
) -> std::result::Result<storage::TxIndex, storage_api::Error> {
Ok(self.storage.tx_index)
Ok(self.storage().tx_index)
}

fn get_native_token(&self) -> storage_api::Result<Address> {
Ok(self.storage.native_token.clone())
Ok(self.storage().native_token.clone())
}
}

impl<D, H> StorageWrite for WlStorage<D, H>
impl<T, D, H> StorageWrite for T
where
T: WriteLogAndStorage<D = D, H = H>,
D: DB + for<'iter> DBIter<'iter>,
H: StorageHasher,
{
Expand All @@ -313,12 +409,18 @@ where
key: &storage::Key,
val: impl AsRef<[u8]>,
) -> storage_api::Result<()> {
self.write_log
let _ = self
.write_log_mut()
.protocol_write(key, val.as_ref().to_vec())
.into_storage_result()
.into_storage_result();
Ok(())
}

fn delete(&mut self, key: &storage::Key) -> storage_api::Result<()> {
self.write_log.protocol_delete(key).into_storage_result()
let _ = self
.write_log_mut()
.protocol_delete(key)
.into_storage_result();
Ok(())
}
}