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

Hash-encode keys in StateMap instead of serializing them with a codec #718

Merged
merged 5 commits into from
Aug 23, 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: 2 additions & 1 deletion module-system/module-implementations/sov-evm/src/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ impl<C: sov_modules_api::Context> Evm<C> {
let cfg_env = get_cfg_env(&block_env, cfg, None);

let hash = evm_tx_recovered.hash();
self.transactions.set(&hash, &tx, working_set);
self.transactions
.set(hash.as_fixed_bytes(), &tx, working_set);

let evm_db: EvmDb<'_, C> = self.get_db(working_set);

Expand Down
4 changes: 2 additions & 2 deletions module-system/module-implementations/sov-evm/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ impl<C: sov_modules_api::Context> Evm<C> {
working_set: &mut WorkingSet<C::Storage>,
) -> RpcResult<Option<Transaction>> {
info!("evm module: eth_getTransactionByHash");
let evm_transaction = self.transactions.get(&hash.into(), working_set);
let evm_transaction = self.transactions.get(hash.as_fixed_bytes(), working_set);
let result = evm_transaction.map(Transaction::try_from).transpose();
result.map_err(|e| to_jsonrpsee_error_object(e, "ETH_RPC_ERROR"))
}
Expand All @@ -75,7 +75,7 @@ impl<C: sov_modules_api::Context> Evm<C> {
working_set: &mut WorkingSet<C::Storage>,
) -> RpcResult<Option<TransactionReceipt>> {
info!("evm module: eth_getTransactionReceipt");
let receipt = self.receipts.get(&hash.into(), working_set);
let receipt = self.receipts.get(hash.as_fixed_bytes(), working_set);
Ok(receipt.map(|r| r.into()))
}

Expand Down
7 changes: 7 additions & 0 deletions module-system/sov-modules-api/src/default_signature.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::hash::Hash;
#[cfg(feature = "native")]
use std::str::FromStr;

Expand Down Expand Up @@ -123,6 +124,12 @@ pub struct DefaultPublicKey {
pub(crate) pub_key: DalekPublicKey,
}

impl Hash for DefaultPublicKey {
vlopes11 marked this conversation as resolved.
Show resolved Hide resolved
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.pub_key.as_bytes().hash(state);
}
}

impl Serialize for DefaultPublicKey {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
Expand Down
3 changes: 3 additions & 0 deletions module-system/sov-modules-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pub mod macros {

use core::fmt::{self, Debug, Display};
use std::collections::{HashMap, HashSet};
use std::hash::Hash;
use std::str::FromStr;

use borsh::{BorshDeserialize, BorshSerialize};
Expand Down Expand Up @@ -193,6 +194,7 @@ pub trait Spec {
type PublicKey: borsh::BorshDeserialize
+ borsh::BorshSerialize
+ Eq
+ Hash
+ Clone
+ Debug
+ PublicKey
Expand All @@ -217,6 +219,7 @@ pub trait Spec {
type PublicKey: borsh::BorshDeserialize
+ borsh::BorshSerialize
+ Eq
+ Hash
+ Clone
+ Debug
+ Send
Expand Down
125 changes: 6 additions & 119 deletions module-system/sov-state/src/codec.rs
Original file line number Diff line number Diff line change
@@ -1,45 +1,10 @@
//! Serialization and deserialization -related logic.

/// A trait for types that can serialize and deserialize keys for storage
/// access.
pub trait StateKeyCodec<K> {
/// Error type that can arise during deserialization.
type KeyError: std::fmt::Debug;

/// Serializes a key into a bytes vector.
///
/// This method **must** not panic as all instances of the key type are
/// supposed to be serializable.
fn encode_key(&self, key: &K) -> Vec<u8>;

/// Tries to deserialize a key from a bytes slice, and returns a
/// [`Result`] with either the deserialized key or an error.
fn try_decode_key(&self, bytes: &[u8]) -> Result<K, Self::KeyError>;

/// Deserializes a key from a bytes slice.
///
/// # Panics
/// Panics if the call to [`StateKeyCodec::try_decode_key`] fails. Use
/// [`StateKeyCodec::try_decode_key`] if you need to gracefully handle
/// errors.
fn decode_key(&self, bytes: &[u8]) -> K {
self.try_decode_key(bytes)
.map_err(|err| {
format!(
"Failed to decode key 0x{}, error: {:?}",
hex::encode(bytes),
err
)
})
.unwrap()
}
}

/// A trait for types that can serialize and deserialize values for storage
/// access.
pub trait StateValueCodec<V> {
/// Error type that can arise during deserialization.
type ValueError: std::fmt::Debug;
type Error: std::fmt::Debug;

/// Serializes a value into a bytes vector.
///
Expand All @@ -49,15 +14,15 @@ pub trait StateValueCodec<V> {

/// Tries to deserialize a value from a bytes slice, and returns a
/// [`Result`] with either the deserialized value or an error.
fn try_decode_value(&self, bytes: &[u8]) -> Result<V, Self::ValueError>;
fn try_decode_value(&self, bytes: &[u8]) -> Result<V, Self::Error>;

/// Deserializes a value from a bytes slice.
///
/// # Panics
/// Panics if the call to [`StateValueCodec::try_decode_value`] fails. Use
/// [`StateValueCodec::try_decode_value`] if you need to gracefully handle
/// errors.
fn decode_value(&self, bytes: &[u8]) -> V {
fn decode_value_unwrap(&self, bytes: &[u8]) -> V {
self.try_decode_value(bytes)
.map_err(|err| {
format!(
Expand All @@ -70,99 +35,21 @@ pub trait StateValueCodec<V> {
}
}

/// A market trait for types that implement both [`StateKeyCodec`] and
/// [`StateValueCodec`].
pub trait StateCodec<K, V>: StateKeyCodec<K> + StateValueCodec<V> {}

impl<K, V, C> StateCodec<K, V> for C where C: StateKeyCodec<K> + StateValueCodec<V> {}

/// A [`StateCodec`] that uses [`borsh`] for all keys and values.
/// A [`StateValueCodec`] that uses [`borsh`] for all values.
#[derive(Debug, Default, PartialEq, Eq, Clone, borsh::BorshDeserialize, borsh::BorshSerialize)]
pub struct BorshCodec;

impl<K> StateKeyCodec<K> for BorshCodec
where
K: borsh::BorshSerialize + borsh::BorshDeserialize,
{
type KeyError = std::io::Error;

fn encode_key(&self, key: &K) -> Vec<u8> {
key.try_to_vec().expect("Failed to serialize key")
}

fn try_decode_key(&self, bytes: &[u8]) -> Result<K, Self::KeyError> {
K::try_from_slice(bytes)
}
}

impl<V> StateValueCodec<V> for BorshCodec
where
V: borsh::BorshSerialize + borsh::BorshDeserialize,
{
type ValueError = std::io::Error;
type Error = std::io::Error;

fn encode_value(&self, value: &V) -> Vec<u8> {
value.try_to_vec().expect("Failed to serialize value")
}

fn try_decode_value(&self, bytes: &[u8]) -> Result<V, Self::ValueError> {
fn try_decode_value(&self, bytes: &[u8]) -> Result<V, Self::Error> {
V::try_from_slice(bytes)
}
}

/// A [`StateCodec`] that uses two different codecs under the hood, one for keys
/// and one for values.
#[derive(Default, Debug, Clone)]
pub struct PairOfCodecs<KC, VC> {
key_codec: KC,
value_codec: VC,
}

impl<KC, VC> PairOfCodecs<KC, VC> {
/// Creates a new [`PairOfCodecs`] from a [`StateKeyCodec`] and a
/// [`StateValueCodec`].
pub fn new(key_codec: KC, value_codec: VC) -> Self {
Self {
key_codec,
value_codec,
}
}
}

impl<K, KC, VC> StateKeyCodec<K> for PairOfCodecs<KC, VC>
where
KC: StateKeyCodec<K>,
{
type KeyError = KC::KeyError;

fn decode_key(&self, bytes: &[u8]) -> K {
self.key_codec.decode_key(bytes)
}

fn try_decode_key(&self, bytes: &[u8]) -> Result<K, Self::KeyError> {
self.key_codec.try_decode_key(bytes)
}

fn encode_key(&self, key: &K) -> Vec<u8> {
self.key_codec.encode_key(key)
}
}

impl<V, KC, VC> StateValueCodec<V> for PairOfCodecs<KC, VC>
where
VC: StateValueCodec<V>,
{
type ValueError = VC::ValueError;

fn decode_value(&self, bytes: &[u8]) -> V {
self.value_codec.decode_value(bytes)
}

fn try_decode_value(&self, bytes: &[u8]) -> Result<V, Self::ValueError> {
self.value_codec.try_decode_value(bytes)
}

fn encode_value(&self, value: &V) -> Vec<u8> {
self.value_codec.encode_value(value)
}
}
28 changes: 14 additions & 14 deletions module-system/sov-state/src/internal_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,44 +42,44 @@ impl StorageInternalCache {
/// Gets a value from the cache or reads it from the provided `ValueReader`.
pub(crate) fn get_or_fetch<S: Storage>(
&mut self,
key: StorageKey,
key: &StorageKey,
value_reader: &S,
witness: &S::Witness,
) -> Option<StorageValue> {
let cache_key = key.clone().as_cache_key();
let cache_value = self.get_value_from_cache(cache_key.clone());
let cache_key = key.to_cache_key();
let cache_value = self.get_value_from_cache(&cache_key);

match cache_value {
cache::ValueExists::Yes(cache_value_exists) => cache_value_exists.map(Into::into),
// If the value does not exist in the cache, then fetch it from an external source.
cache::ValueExists::No => {
let storage_value = value_reader.get(key, witness);
let cache_value = storage_value.as_ref().map(|v| v.clone().as_cache_value());
let cache_value = storage_value.as_ref().map(|v| v.clone().into_cache_value());

self.add_read(cache_key, cache_value);
storage_value
}
}
}

pub fn try_get(&self, key: StorageKey) -> ValueExists {
let cache_key = key.as_cache_key();
self.get_value_from_cache(cache_key)
pub fn try_get(&self, key: &StorageKey) -> ValueExists {
let cache_key = key.to_cache_key();
self.get_value_from_cache(&cache_key)
}

pub(crate) fn set(&mut self, key: StorageKey, value: StorageValue) {
let cache_key = key.as_cache_key();
let cache_value = value.as_cache_value();
pub(crate) fn set(&mut self, key: &StorageKey, value: StorageValue) {
let cache_key = key.to_cache_key();
let cache_value = value.into_cache_value();
self.tx_cache.add_write(cache_key, Some(cache_value));
}

pub(crate) fn delete(&mut self, key: StorageKey) {
let cache_key = key.as_cache_key();
pub(crate) fn delete(&mut self, key: &StorageKey) {
let cache_key = key.to_cache_key();
self.tx_cache.add_write(cache_key, None);
}

fn get_value_from_cache(&self, cache_key: CacheKey) -> cache::ValueExists {
self.tx_cache.get_value(&cache_key)
fn get_value_from_cache(&self, cache_key: &CacheKey) -> cache::ValueExists {
self.tx_cache.get_value(cache_key)
}

pub fn merge_left(
Expand Down
2 changes: 1 addition & 1 deletion module-system/sov-state/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ mod state_tests;
use std::fmt::Display;
use std::str;

pub use map::{MapError, StateMap};
pub use map::{StateMap, StateMapError};
#[cfg(feature = "native")]
pub use prover_storage::{delete_storage, ProverStorage};
pub use scratchpad::*;
Expand Down
Loading