Skip to content

Commit

Permalink
Merge branch 'tomas/refactor-storage-prefix-iter' (#335)
Browse files Browse the repository at this point in the history
* tomas/refactor-storage-prefix-iter:
  changelog: add #335
  wasm checksums update
  test/vm_host_env: refactor prefix iter tests with new `iter_prefix` fn
  storage_api: build a nicer `iter_prefix` function on top of StorageRead
  • Loading branch information
tzemanovic committed Aug 22, 2022
2 parents d339f19 + fec7220 commit c4cca9d
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 44 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- Added a simpler prefix iterator API that returns `std::iter::Iterator` with
the storage keys parsed and a variant that also decodes stored values with
Borsh ([#335](https://github.com/anoma/namada/pull/335))
66 changes: 66 additions & 0 deletions shared/src/ledger/storage_api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,69 @@ pub trait StorageWrite {
/// Delete a value at the given key from storage.
fn delete(&mut self, key: &storage::Key) -> Result<()>;
}

/// Iterate items matching the given prefix.
pub fn iter_prefix_bytes<'a>(
storage: &'a impl StorageRead<'a>,
prefix: &crate::types::storage::Key,
) -> Result<impl Iterator<Item = Result<(storage::Key, Vec<u8>)>> + 'a> {
let iter = storage.iter_prefix(prefix)?;
let iter = itertools::unfold(iter, |iter| {
match storage.iter_next(iter) {
Ok(Some((key, val))) => {
let key = match storage::Key::parse(key).into_storage_result() {
Ok(key) => key,
Err(err) => {
// Propagate key encoding errors into Iterator's Item
return Some(Err(err));
}
};
Some(Ok((key, val)))
}
Ok(None) => None,
Err(err) => {
// Propagate `iter_next` errors into Iterator's Item
Some(Err(err))
}
}
});
Ok(iter)
}

/// Iterate Borsh encoded items matching the given prefix.
pub fn iter_prefix<'a, T>(
storage: &'a impl StorageRead<'a>,
prefix: &crate::types::storage::Key,
) -> Result<impl Iterator<Item = Result<(storage::Key, T)>> + 'a>
where
T: BorshDeserialize,
{
let iter = storage.iter_prefix(prefix)?;
let iter = itertools::unfold(iter, |iter| {
match storage.iter_next(iter) {
Ok(Some((key, val))) => {
let key = match storage::Key::parse(key).into_storage_result() {
Ok(key) => key,
Err(err) => {
// Propagate key encoding errors into Iterator's Item
return Some(Err(err));
}
};
let val = match T::try_from_slice(&val).into_storage_result() {
Ok(val) => val,
Err(err) => {
// Propagate val encoding errors into Iterator's Item
return Some(Err(err));
}
};
Some(Ok((key, val)))
}
Ok(None) => None,
Err(err) => {
// Propagate `iter_next` errors into Iterator's Item
Some(Err(err))
}
}
});
Ok(iter)
}
51 changes: 23 additions & 28 deletions tests/src/vm_host_env/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,11 @@ mod tests {
tx_host_env::init();

let empty_key = storage::Key::parse("empty").unwrap();
let mut iter = tx::ctx().iter_prefix(&empty_key).unwrap();
let mut iter =
namada_tx_prelude::iter_prefix_bytes(tx::ctx(), &empty_key)
.unwrap();
assert!(
tx::ctx().iter_next(&mut iter).unwrap().is_none(),
iter.next().is_none(),
"Trying to iter a prefix that doesn't have any matching keys \
should yield an empty iterator."
);
Expand All @@ -167,15 +169,12 @@ mod tests {
});

// Then try to iterate over their prefix
let iter = tx::ctx().iter_prefix(&prefix).unwrap();
let iter = itertools::unfold(iter, |iter| {
if let Ok(Some((key, value))) = tx::ctx().iter_next(iter) {
let decoded_value = i32::try_from_slice(&value[..]).unwrap();
return Some((key, decoded_value));
}
None
let iter = namada_tx_prelude::iter_prefix(tx::ctx(), &prefix)
.unwrap()
.map(|item| item.unwrap());
let expected = (0..10).map(|i| {
(storage::Key::parse(format!("{}/{}", prefix, i)).unwrap(), i)
});
let expected = (0..10).map(|i| (format!("{}/{}", prefix, i), i));
itertools::assert_equal(iter.sorted(), expected.sorted());
}

Expand Down Expand Up @@ -380,29 +379,25 @@ mod tests {
tx::ctx().write(&new_key, 11_i32).unwrap();
});

let iter_pre = vp::CTX.iter_prefix(&prefix).unwrap();
let iter_pre = itertools::unfold(iter_pre, |iter| {
if let Ok(Some((key, value))) = vp::CTX.iter_pre_next(iter) {
if let Ok(decoded_value) = i32::try_from_slice(&value[..]) {
return Some((key, decoded_value));
}
}
None
let ctx_pre = vp::CTX.pre();
let iter_pre = namada_vp_prelude::iter_prefix(&ctx_pre, &prefix)
.unwrap()
.map(|item| item.unwrap());
let expected_pre = (0..10).map(|i| {
(storage::Key::parse(format!("{}/{}", prefix, i)).unwrap(), i)
});
let expected_pre = (0..10).map(|i| (format!("{}/{}", prefix, i), i));
itertools::assert_equal(iter_pre.sorted(), expected_pre.sorted());

let iter_post = vp::CTX.iter_prefix(&prefix).unwrap();
let iter_post = itertools::unfold(iter_post, |iter| {
if let Ok(Some((key, value))) = vp::CTX.iter_post_next(iter) {
let decoded_value = i32::try_from_slice(&value[..]).unwrap();
return Some((key, decoded_value));
}
None
});
let ctx_post = vp::CTX.post();
let iter_post = namada_vp_prelude::iter_prefix(&ctx_post, &prefix)
.unwrap()
.map(|item| item.unwrap());
let expected_post = (0..10).map(|i| {
let val = if i == 5 { 100 } else { i };
(format!("{}/{}", prefix, i), val)
(
storage::Key::parse(format!("{}/{}", prefix, i)).unwrap(),
val,
)
});
itertools::assert_equal(iter_post.sorted(), expected_post.sorted());
}
Expand Down
4 changes: 3 additions & 1 deletion tx_prelude/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ pub use namada::ledger::governance::storage as gov_storage;
pub use namada::ledger::parameters::storage as parameters_storage;
pub use namada::ledger::storage::types::encode;
use namada::ledger::storage_api;
pub use namada::ledger::storage_api::{StorageRead, StorageWrite};
pub use namada::ledger::storage_api::{
iter_prefix, iter_prefix_bytes, StorageRead, StorageWrite,
};
pub use namada::ledger::treasury::storage as treasury_storage;
pub use namada::ledger::tx_env::TxEnv;
pub use namada::proto::{Signed, SignedTxData};
Expand Down
10 changes: 6 additions & 4 deletions vp_prelude/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ use std::marker::PhantomData;
pub use borsh::{BorshDeserialize, BorshSerialize};
pub use error::*;
pub use namada::ledger::governance::storage as gov_storage;
pub use namada::ledger::storage_api::{self, StorageRead};
pub use namada::ledger::storage_api::{
self, iter_prefix, iter_prefix_bytes, StorageRead,
};
pub use namada::ledger::vp_env::VpEnv;
pub use namada::ledger::{parameters, pos as proof_of_stake};
pub use namada::proto::{Signed, SignedTxData};
Expand Down Expand Up @@ -332,7 +334,7 @@ impl StorageRead<'_> for CtxPreStorageRead<'_> {
prefix: &storage::Key,
) -> Result<Self::PrefixIter, storage_api::Error> {
// Note that this is the same as `CtxPostStorageRead`
iter_prefix(prefix)
iter_prefix_impl(prefix)
}

fn iter_next(
Expand Down Expand Up @@ -395,7 +397,7 @@ impl StorageRead<'_> for CtxPostStorageRead<'_> {
prefix: &storage::Key,
) -> Result<Self::PrefixIter, storage_api::Error> {
// Note that this is the same as `CtxPreStorageRead`
iter_prefix(prefix)
iter_prefix_impl(prefix)
}

fn iter_next(
Expand Down Expand Up @@ -426,7 +428,7 @@ impl StorageRead<'_> for CtxPostStorageRead<'_> {
}
}

fn iter_prefix(
fn iter_prefix_impl(
prefix: &storage::Key,
) -> Result<KeyValIterator<(String, Vec<u8>)>, storage_api::Error> {
let prefix = prefix.to_string();
Expand Down
22 changes: 11 additions & 11 deletions wasm/checksums.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
{
"tx_bond.wasm": "tx_bond.1954b4909bf4e43f09b8a0da2fceb1aa0e2313d0596fadd5151b1b28e369ca0e.wasm",
"tx_from_intent.wasm": "tx_from_intent.e065a661f424cf205a412f68762543f558300d14edd08774109b41edcddba13b.wasm",
"tx_ibc.wasm": "tx_ibc.6ca598ab75afa183d399f74db60dc39a843ae7583ba4cbbfbf6e1b0be89010a6.wasm",
"tx_init_account.wasm": "tx_init_account.c8bae19a17172e8843ac40b343c929e50f85fc56c351d02914ee42d81e6053bc.wasm",
"tx_init_nft.wasm": "tx_init_nft.8d72699664afd7fc7801dcf09e3d1fec04dd55b98a3ed1dc30aae8010898bc2c.wasm",
"tx_init_proposal.wasm": "tx_init_proposal.13efe62a687d0688b615a9cc869f35ee455a52e7c175ed594ab23cf3ae609050.wasm",
"tx_init_validator.wasm": "tx_init_validator.3ba02ac038acfe50ce07be1786d6ba5ab334b31384b1466a4c00b4cb4044df7d.wasm",
"tx_bond.wasm": "tx_bond.7474de3297f6e2c9e556e72ed81d017015f8d012b9234aabf2796d15517e7418.wasm",
"tx_from_intent.wasm": "tx_from_intent.0d468574af51284e1ec8018158be5ec0d8931183ed859c91c8ac4ebad062c66d.wasm",
"tx_ibc.wasm": "tx_ibc.5d5c535defa4a49883f4c68a55b534d79442883db557a00e2881ba7cc7dde1ae.wasm",
"tx_init_account.wasm": "tx_init_account.dc685f0fd10e0f8979285d9c301f34aa50679d018d6f47d3d9397d4e9fc8db6c.wasm",
"tx_init_nft.wasm": "tx_init_nft.570d2e0fd2e65f3b250725354ec8ebaf6dc735c32eca46475b8f1041e036aef7.wasm",
"tx_init_proposal.wasm": "tx_init_proposal.9beb3e657abd540f1af1717ad0c2d095bf48356f0eb75bbd36686e1417832a39.wasm",
"tx_init_validator.wasm": "tx_init_validator.f2f66a6dd9367a4ae1ce19264f7cc7d8b6e8c1ba2ed727a1ebddb39c69b7fb57.wasm",
"tx_mint_nft.wasm": "tx_mint_nft.a696a518c3a3cfe2a9a611dc1e35ab8907a46fca35deea977c810aa315eda8c2.wasm",
"tx_transfer.wasm": "tx_transfer.33206497969f293a4ece5f816b43a4794b2bef2ba792300d89c25d38f4fb7eea.wasm",
"tx_transfer.wasm": "tx_transfer.2c8f9eb1b8eb2375f22d012a3baafea7d33c6683a9b5ef93007a786670ecad0b.wasm",
"tx_unbond.wasm": "tx_unbond.89b65c1eb0bdefadfcb900820514a0d740f8debb2c9f9d5572ed50d774a064ea.wasm",
"tx_update_vp.wasm": "tx_update_vp.a74c98cb8d5230875e212807a86c9c7756ab121afe9332a91544c2ad08d9cdab.wasm",
"tx_vote_proposal.wasm": "tx_vote_proposal.f34d1ed3bc6f9a7b0ee8f7a209a77f63149b9a166fb433dedb305d5adb5fad05.wasm",
"tx_withdraw.wasm": "tx_withdraw.0bb13fdf61f6ab635e15e5abba3b72ab833e9e33d10794d9331acb33d777c8d5.wasm",
"tx_withdraw.wasm": "tx_withdraw.ac45cb688395c619617fd5510710d60562d919f7c89c095226f219f9a808f9b6.wasm",
"vp_nft.wasm": "vp_nft.7f524b462d5d23a08bebbae517a154bc3d44436a435ed37b44aa816f20ae86ff.wasm",
"vp_testnet_faucet.wasm": "vp_testnet_faucet.cdd0e15059c0b4194ae1144fa6307d28bb2c7b96cbdc5f9c6f08c16059a7b7db.wasm",
"vp_testnet_faucet.wasm": "vp_testnet_faucet.44a8266b23abdddc66cbcf9dfdae74f1efad03bafbb40f2a440185b2f54ab253.wasm",
"vp_token.wasm": "vp_token.1f415edb5a4d15feea249271c8efc9ea7a0b9873b6cfe1e2774ac5db58254700.wasm",
"vp_user.wasm": "vp_user.165ec95f97d5e9e6931a9b32a18b8c02e8f89028c52e67d0a6fb09639512ce53.wasm"
"vp_user.wasm": "vp_user.45d9dbed3af01ca832f94dd0fe27494d572749d5baf5f8e421849dd7cd46333f.wasm"
}

0 comments on commit c4cca9d

Please sign in to comment.