diff --git a/module-system/module-implementations/sov-evm/src/call.rs b/module-system/module-implementations/sov-evm/src/call.rs index 13d40318e..3917115e1 100644 --- a/module-system/module-implementations/sov-evm/src/call.rs +++ b/module-system/module-implementations/sov-evm/src/call.rs @@ -35,7 +35,8 @@ impl Evm { 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); diff --git a/module-system/module-implementations/sov-evm/src/query.rs b/module-system/module-implementations/sov-evm/src/query.rs index c716cccab..d4b51ca00 100644 --- a/module-system/module-implementations/sov-evm/src/query.rs +++ b/module-system/module-implementations/sov-evm/src/query.rs @@ -62,7 +62,7 @@ impl Evm { working_set: &mut WorkingSet, ) -> RpcResult> { 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")) } @@ -75,7 +75,7 @@ impl Evm { working_set: &mut WorkingSet, ) -> RpcResult> { 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())) } diff --git a/module-system/sov-modules-api/src/default_signature.rs b/module-system/sov-modules-api/src/default_signature.rs index 38c24837c..8f03d9131 100644 --- a/module-system/sov-modules-api/src/default_signature.rs +++ b/module-system/sov-modules-api/src/default_signature.rs @@ -1,3 +1,4 @@ +use std::hash::Hash; #[cfg(feature = "native")] use std::str::FromStr; @@ -123,6 +124,12 @@ pub struct DefaultPublicKey { pub(crate) pub_key: DalekPublicKey, } +impl Hash for DefaultPublicKey { + fn hash(&self, state: &mut H) { + self.pub_key.as_bytes().hash(state); + } +} + impl Serialize for DefaultPublicKey { fn serialize(&self, serializer: S) -> Result where diff --git a/module-system/sov-modules-api/src/lib.rs b/module-system/sov-modules-api/src/lib.rs index 8f324fc02..d75ff8238 100644 --- a/module-system/sov-modules-api/src/lib.rs +++ b/module-system/sov-modules-api/src/lib.rs @@ -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}; @@ -193,6 +194,7 @@ pub trait Spec { type PublicKey: borsh::BorshDeserialize + borsh::BorshSerialize + Eq + + Hash + Clone + Debug + PublicKey @@ -217,6 +219,7 @@ pub trait Spec { type PublicKey: borsh::BorshDeserialize + borsh::BorshSerialize + Eq + + Hash + Clone + Debug + Send diff --git a/module-system/sov-state/src/codec.rs b/module-system/sov-state/src/codec.rs index ae339d5f6..755a238e3 100644 --- a/module-system/sov-state/src/codec.rs +++ b/module-system/sov-state/src/codec.rs @@ -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 { - /// 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; - - /// 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; - - /// 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 { /// Error type that can arise during deserialization. - type ValueError: std::fmt::Debug; + type Error: std::fmt::Debug; /// Serializes a value into a bytes vector. /// @@ -49,7 +14,7 @@ pub trait StateValueCodec { /// 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; + fn try_decode_value(&self, bytes: &[u8]) -> Result; /// Deserializes a value from a bytes slice. /// @@ -57,7 +22,7 @@ pub trait StateValueCodec { /// 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!( @@ -70,99 +35,21 @@ pub trait StateValueCodec { } } -/// A market trait for types that implement both [`StateKeyCodec`] and -/// [`StateValueCodec`]. -pub trait StateCodec: StateKeyCodec + StateValueCodec {} - -impl StateCodec for C where C: StateKeyCodec + StateValueCodec {} - -/// 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 StateKeyCodec for BorshCodec -where - K: borsh::BorshSerialize + borsh::BorshDeserialize, -{ - type KeyError = std::io::Error; - - fn encode_key(&self, key: &K) -> Vec { - key.try_to_vec().expect("Failed to serialize key") - } - - fn try_decode_key(&self, bytes: &[u8]) -> Result { - K::try_from_slice(bytes) - } -} - impl StateValueCodec 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 { value.try_to_vec().expect("Failed to serialize value") } - fn try_decode_value(&self, bytes: &[u8]) -> Result { + fn try_decode_value(&self, bytes: &[u8]) -> Result { 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 { - key_codec: KC, - value_codec: VC, -} - -impl PairOfCodecs { - /// 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 StateKeyCodec for PairOfCodecs -where - KC: StateKeyCodec, -{ - 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 { - self.key_codec.try_decode_key(bytes) - } - - fn encode_key(&self, key: &K) -> Vec { - self.key_codec.encode_key(key) - } -} - -impl StateValueCodec for PairOfCodecs -where - VC: StateValueCodec, -{ - 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 { - self.value_codec.try_decode_value(bytes) - } - - fn encode_value(&self, value: &V) -> Vec { - self.value_codec.encode_value(value) - } -} diff --git a/module-system/sov-state/src/internal_cache.rs b/module-system/sov-state/src/internal_cache.rs index 790dfd636..efda9f5b5 100644 --- a/module-system/sov-state/src/internal_cache.rs +++ b/module-system/sov-state/src/internal_cache.rs @@ -42,19 +42,19 @@ impl StorageInternalCache { /// Gets a value from the cache or reads it from the provided `ValueReader`. pub(crate) fn get_or_fetch( &mut self, - key: StorageKey, + key: &StorageKey, value_reader: &S, witness: &S::Witness, ) -> Option { - 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 @@ -62,24 +62,24 @@ impl StorageInternalCache { } } - 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( diff --git a/module-system/sov-state/src/lib.rs b/module-system/sov-state/src/lib.rs index be765c793..577bd79f8 100644 --- a/module-system/sov-state/src/lib.rs +++ b/module-system/sov-state/src/lib.rs @@ -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::*; diff --git a/module-system/sov-state/src/map.rs b/module-system/sov-state/src/map.rs index 3e24e01a2..dee4a2ba3 100644 --- a/module-system/sov-state/src/map.rs +++ b/module-system/sov-state/src/map.rs @@ -1,8 +1,10 @@ +use std::borrow::Borrow; +use std::hash::Hash; use std::marker::PhantomData; use thiserror::Error; -use crate::codec::{BorshCodec, StateCodec}; +use crate::codec::{BorshCodec, StateValueCodec}; use crate::storage::StorageKey; use crate::{Prefix, Storage, WorkingSet}; @@ -10,54 +12,37 @@ use crate::{Prefix, Storage, WorkingSet}; /// /// # Type parameters /// [`StateMap`] is generic over: -/// - a key type (`K`); -/// - a value type (`V`); -/// - a [`StateCodec`] (`C`). -#[derive(borsh::BorshDeserialize, borsh::BorshSerialize, Debug, PartialEq, Clone)] -pub struct StateMap -where - C: StateCodec, -{ +/// - a key type `K`; +/// - a value type `V`; +/// - a [`StateValueCodec`] `VC`. +#[derive(Debug, Clone, PartialEq, borsh::BorshDeserialize, borsh::BorshSerialize)] +pub struct StateMap { _phantom: (PhantomData, PhantomData), - pub(crate) codec: C, + value_codec: VC, prefix: Prefix, } -/// Error type for [`StateMap::get`] method. +/// Error type for the [`StateMap::get`] method. #[derive(Debug, Error)] -pub enum MapError { +pub enum StateMapError { #[error("Value not found for prefix: {0} and: storage key {1}")] MissingValue(Prefix, StorageKey), } -impl StateMap -where - BorshCodec: StateCodec, -{ +impl StateMap { /// Creates a new [`StateMap`] with the given prefix and the default - /// [`StateCodec`] (i.e. [`BorshCodec`]). + /// [`StateValueCodec`] (i.e. [`BorshCodec`]). pub fn new(prefix: Prefix) -> Self { - Self { - _phantom: (PhantomData, PhantomData), - codec: BorshCodec, - prefix, - } + Self::with_codec(prefix, BorshCodec) } } -impl StateMap -where - C: StateCodec, -{ - /// Creates a new [`StateMap`] with the given prefix and codec. - /// - /// Note that `codec` must implement [`StateCodec`]. You can use - /// [`PairOfCodecs`](crate::codec::PairOfCodecs) if you wish to decouple key - /// and value codecs. - pub fn with_codec(prefix: Prefix, codec: C) -> Self { +impl StateMap { + /// Creates a new [`StateMap`] with the given prefix and [`StateValueCodec`]. + pub fn with_codec(prefix: Prefix, codec: VC) -> Self { Self { _phantom: (PhantomData, PhantomData), - codec, + value_codec: codec, prefix, } } @@ -66,53 +51,123 @@ where pub fn prefix(&self) -> &Prefix { &self.prefix } +} +impl StateMap +where + K: Hash + Eq, + VC: StateValueCodec, +{ /// Inserts a key-value pair into the map. - pub fn set(&self, key: &K, value: &V, working_set: &mut WorkingSet) { - working_set.set_value(self.prefix(), &self.codec, key, value) + /// + /// Much like [`StateMap::get`], the key may be any borrowed form of the + /// map’s key type. + pub fn set(&self, key: &Q, value: &V, working_set: &mut WorkingSet) + where + K: Borrow, + Q: Hash + Eq + ?Sized, + { + working_set.set_value(self.prefix(), key, value, &self.value_codec) } - /// Returns the value corresponding to the key or None if key is absent in the StateMap. - pub fn get(&self, key: &K, working_set: &mut WorkingSet) -> Option { - working_set.get_value(self.prefix(), &self.codec, key) + /// Returns the value corresponding to the key, or [`None`] if the map + /// doesn't contain the key. + /// + /// # Examples + /// + /// The key may be any borrowed form of the map’s key type. Note that + /// [`Hash`] and [`Eq`] on the borrowed form must match those for the key + /// type. + /// + /// ``` + /// use sov_state::{StateMap, Storage, WorkingSet}; + /// + /// fn foo(map: StateMap, u64>, key: &[u8], ws: &mut WorkingSet) -> Option + /// where + /// S: Storage, + /// { + /// // We perform the `get` with a slice, and not the `Vec`. it is so because `Vec` borrows + /// // `[T]`. + /// map.get(key, ws) + /// } + /// ``` + /// + /// If the map's key type does not implement [`Borrow`] for your desired + /// target type, you'll have to convert the key to something else. An + /// example of this would be "slicing" an array to use in [`Vec`]-keyed + /// maps: + /// + /// ``` + /// use sov_state::{StateMap, Storage, WorkingSet}; + /// + /// fn foo(map: StateMap, u64>, key: [u8; 32], ws: &mut WorkingSet) -> Option + /// where + /// S: Storage, + /// { + /// map.get(&key[..], ws) + /// } + /// ``` + pub fn get(&self, key: &Q, working_set: &mut WorkingSet) -> Option + where + K: Borrow, + Q: Hash + Eq + ?Sized, + { + working_set.get_value(self.prefix(), key, &self.value_codec) } - /// Returns the value corresponding to the key or [`MapError`] if key is absent in + /// Returns the value corresponding to the key or [`StateMapError`] if key is absent in /// the map. - pub fn get_or_err( + pub fn get_or_err( &self, - key: &K, + key: &Q, working_set: &mut WorkingSet, - ) -> Result { + ) -> Result + where + K: Borrow, + Q: Hash + Eq + ?Sized, + { self.get(key, working_set).ok_or_else(|| { - MapError::MissingValue( - self.prefix().clone(), - StorageKey::new(self.prefix(), key, &self.codec), - ) + StateMapError::MissingValue(self.prefix().clone(), StorageKey::new(self.prefix(), key)) }) } - /// Removes a key from the StateMap, returning the corresponding value (or None if the key is absent). - pub fn remove(&self, key: &K, working_set: &mut WorkingSet) -> Option { - working_set.remove_value(self.prefix(), &self.codec, key) + /// Removes a key from the map, returning the corresponding value (or + /// [`None`] if the key is absent). + pub fn remove(&self, key: &Q, working_set: &mut WorkingSet) -> Option + where + K: Borrow, + Q: Hash + Eq + ?Sized, + { + working_set.remove_value(self.prefix(), key, &self.value_codec) } - /// Removes a key from the StateMap, returning the corresponding value (or Error if the key is absent). - pub fn remove_or_err( + /// Removes a key from the map, returning the corresponding value (or + /// [`StateMapError`] if the key is absent). + /// + /// Use [`StateMap::remove`] if you want an [`Option`] instead of a [`Result`]. + pub fn remove_or_err( &self, - key: &K, + key: &Q, working_set: &mut WorkingSet, - ) -> Result { + ) -> Result + where + K: Borrow, + Q: Hash + Eq + ?Sized, + { self.remove(key, working_set).ok_or_else(|| { - MapError::MissingValue( - self.prefix().clone(), - StorageKey::new(self.prefix(), key, &self.codec), - ) + StateMapError::MissingValue(self.prefix().clone(), StorageKey::new(self.prefix(), key)) }) } - /// Deletes a key from the StateMap. - pub fn delete(&self, key: &K, working_set: &mut WorkingSet) { - working_set.delete_value(self.prefix(), &self.codec, key); + /// Deletes a key-value pair from the map. + /// + /// This is equivalent to [`StateMap::remove`], but doesn't deserialize and + /// return the value beforing deletion. + pub fn delete(&self, key: &Q, working_set: &mut WorkingSet) + where + K: Borrow, + Q: Hash + Eq + ?Sized, + { + working_set.delete_value(self.prefix(), key); } } diff --git a/module-system/sov-state/src/prover_storage.rs b/module-system/sov-state/src/prover_storage.rs index 28fe20839..42f8ea8fa 100644 --- a/module-system/sov-state/src/prover_storage.rs +++ b/module-system/sov-state/src/prover_storage.rs @@ -41,7 +41,7 @@ impl ProverStorage { }) } - fn read_value(&self, key: StorageKey) -> Option { + fn read_value(&self, key: &StorageKey) -> Option { match self .db .get_value_option_by_key(self.db.get_next_version(), key.as_ref()) @@ -68,7 +68,7 @@ impl Storage for ProverStorage { Self::with_path(config.path.as_path()) } - fn get(&self, key: StorageKey, witness: &Self::Witness) -> Option { + fn get(&self, key: &StorageKey, witness: &Self::Witness) -> Option { let val = self.read_value(key); witness.add_hint(val.clone()); val @@ -246,7 +246,7 @@ mod test { .validate_and_commit(cache, &witness) .expect("storage is valid"); - assert_eq!(test.value, prover_storage.get(test.key, &witness).unwrap()); + assert_eq!(test.value, prover_storage.get(&test.key, &witness).unwrap()); assert_eq!(prover_storage.db.get_next_version(), test.version + 1) } } @@ -257,7 +257,7 @@ mod test { for test in tests { assert_eq!( test.value, - storage.get(test.key, &Default::default()).unwrap() + storage.get(&test.key, &Default::default()).unwrap() ); } } @@ -290,7 +290,10 @@ mod test { { let prover_storage = ProverStorage::::with_path(path).unwrap(); assert!(!prover_storage.is_empty()); - assert_eq!(value, prover_storage.get(key, &Default::default()).unwrap()); + assert_eq!( + value, + prover_storage.get(&key, &Default::default()).unwrap() + ); } } } diff --git a/module-system/sov-state/src/scratchpad.rs b/module-system/sov-state/src/scratchpad.rs index 271c39f44..1badd0ec5 100644 --- a/module-system/sov-state/src/scratchpad.rs +++ b/module-system/sov-state/src/scratchpad.rs @@ -1,10 +1,11 @@ use std::collections::HashMap; use std::fmt::Debug; +use std::hash::Hash; use sov_first_read_last_write_cache::{CacheKey, CacheValue}; use sov_rollup_interface::stf::Event; -use crate::codec::{StateCodec, StateKeyCodec, StateValueCodec}; +use crate::codec::StateValueCodec; use crate::internal_cache::{OrderedReadsAndWrites, StorageInternalCache}; use crate::storage::{StorageKey, StorageValue}; use crate::{Prefix, Storage}; @@ -53,7 +54,7 @@ impl StateCheckpoint { } } - pub fn get(&mut self, key: StorageKey) -> Option { + pub fn get(&mut self, key: &StorageKey) -> Option { self.delta.get(key) } @@ -135,82 +136,85 @@ impl WorkingSet { } impl WorkingSet { - pub(crate) fn set_value( + pub(crate) fn set_value( &mut self, prefix: &Prefix, - codec: &C, storage_key: &K, value: &V, + codec: &VC, ) where - C: StateCodec, + K: Hash + Eq + ?Sized, + VC: StateValueCodec, { - let storage_key = StorageKey::new(prefix, storage_key, codec); + let storage_key = StorageKey::new(prefix, storage_key); let storage_value = StorageValue::new(value, codec); self.set(storage_key, storage_value); } - pub(crate) fn get_value( + pub(crate) fn get_value( &mut self, prefix: &Prefix, - codec: &C, storage_key: &K, + codec: &VC, ) -> Option where - C: StateCodec, + K: Hash + Eq + ?Sized, + VC: StateValueCodec, { - let storage_key = StorageKey::new(prefix, storage_key, codec); - self.get_decoded(codec, storage_key) + let storage_key = StorageKey::new(prefix, storage_key); + self.get_decoded(storage_key, codec) } - pub(crate) fn remove_value( + pub(crate) fn remove_value( &mut self, prefix: &Prefix, - codec: &C, storage_key: &K, + codec: &VC, ) -> Option where - C: StateCodec, + K: Hash + Eq + ?Sized, + VC: StateValueCodec, { - let storage_key = StorageKey::new(prefix, storage_key, codec); - let storage_value = self.get_decoded(codec, storage_key.clone())?; + let storage_key = StorageKey::new(prefix, storage_key); + let storage_value = self.get_decoded(storage_key.clone(), codec)?; self.delete(storage_key); Some(storage_value) } - pub(crate) fn delete_value(&mut self, prefix: &Prefix, codec: &C, storage_key: &K) + pub(crate) fn delete_value(&mut self, prefix: &Prefix, storage_key: &K) where - C: StateKeyCodec, + K: Hash + Eq + ?Sized, { - let storage_key = StorageKey::new(prefix, storage_key, codec); + let storage_key = StorageKey::new(prefix, storage_key); self.delete(storage_key); } - fn get_decoded(&mut self, codec: &C, storage_key: StorageKey) -> Option + fn get_decoded(&mut self, storage_key: StorageKey, codec: &VC) -> Option where - C: StateValueCodec, + VC: StateValueCodec, { let storage_value = self.get(storage_key)?; - Some(codec.decode_value(storage_value.value())) + Some(codec.decode_value_unwrap(storage_value.value())) } } impl RevertableDelta { fn get(&mut self, key: StorageKey) -> Option { - let key = key.as_cache_key(); + let key = key.to_cache_key(); if let Some(value) = self.writes.get(&key) { return value.clone().map(Into::into); } - self.inner.get(key.into()) + self.inner.get(&key.into()) } fn set(&mut self, key: StorageKey, value: StorageValue) { self.writes - .insert(key.as_cache_key(), Some(value.as_cache_value())); + .insert(key.to_cache_key(), Some(value.into_cache_value())); } fn delete(&mut self, key: StorageKey) { - self.writes.insert(key.as_cache_key(), None); + self.writes.insert(key.to_cache_key(), None); } } @@ -220,9 +224,9 @@ impl RevertableDelta { for (k, v) in self.writes.into_iter() { if let Some(v) = v { - inner.set(k.into(), v.into()); + inner.set(&k.into(), v.into()); } else { - inner.delete(k.into()); + inner.delete(&k.into()); } } @@ -266,15 +270,15 @@ impl Debug for Delta { } impl Delta { - fn get(&mut self, key: StorageKey) -> Option { + fn get(&mut self, key: &StorageKey) -> Option { self.cache.get_or_fetch(key, &self.inner, &self.witness) } - fn set(&mut self, key: StorageKey, value: StorageValue) { + fn set(&mut self, key: &StorageKey, value: StorageValue) { self.cache.set(key, value) } - fn delete(&mut self, key: StorageKey) { + fn delete(&mut self, key: &StorageKey) { self.cache.delete(key) } } diff --git a/module-system/sov-state/src/storage.rs b/module-system/sov-state/src/storage.rs index eaa3b5083..e6046840e 100644 --- a/module-system/sov-state/src/storage.rs +++ b/module-system/sov-state/src/storage.rs @@ -1,4 +1,5 @@ use std::fmt::Display; +use std::hash::Hash; use std::sync::Arc; use anyhow::ensure; @@ -8,7 +9,7 @@ use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use sov_first_read_last_write_cache::{CacheKey, CacheValue}; -use crate::codec::{StateKeyCodec, StateValueCodec}; +use crate::codec::StateValueCodec; use crate::internal_cache::OrderedReadsAndWrites; use crate::utils::AlignedVec; use crate::witness::Witness; @@ -31,7 +32,13 @@ impl StorageKey { self.key.clone() } - pub fn as_cache_key(self) -> CacheKey { + pub fn to_cache_key(&self) -> CacheKey { + CacheKey { + key: self.key.clone(), + } + } + + pub fn into_cache_key(self) -> CacheKey { CacheKey { key: self.key } } } @@ -50,11 +57,11 @@ impl Display for StorageKey { impl StorageKey { /// Creates a new StorageKey that combines a prefix and a key. - pub fn new(prefix: &Prefix, key: &K, codec: &C) -> Self + pub fn new(prefix: &Prefix, key: &K) -> Self where - C: StateKeyCodec, + K: Hash + ?Sized, { - let encoded_key = codec.encode_key(key); + let encoded_key = nohash_serialize(key); let encoded_key = AlignedVec::new(encoded_key); let full_key = Vec::::with_capacity(prefix.len() + encoded_key.len()); @@ -68,6 +75,26 @@ impl StorageKey { } } +// Serializes a value into a `Vec` using `std::hash::Hasher` +// writer methods, but without actually ever hashing anything. +fn nohash_serialize(item: T) -> Vec { + struct NoHasher(Vec); + + impl std::hash::Hasher for NoHasher { + fn finish(&self) -> u64 { + 0 + } + + fn write(&mut self, bytes: &[u8]) { + self.0.extend_from_slice(bytes); + } + } + + let mut hasher = NoHasher(vec![]); + item.hash(&mut hasher); + hasher.0 +} + /// A serialized value suitable for storing. Internally uses an Arc> for cheap cloning. #[derive( Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize, Serialize, Deserialize, Default, @@ -94,9 +121,9 @@ impl From> for StorageValue { impl StorageValue { /// Create a new storage value by serializing the input with the given codec. - pub fn new(value: &V, codec: &C) -> Self + pub fn new(value: &V, codec: &VC) -> Self where - C: StateValueCodec, + VC: StateValueCodec, { let encoded_value = codec.encode_value(value); Self { @@ -109,8 +136,8 @@ impl StorageValue { &self.value } - /// Convert this value into a `CacheValue`. - pub fn as_cache_value(self) -> CacheValue { + /// Convert this value into a [`CacheValue`]. + pub fn into_cache_value(self) -> CacheValue { CacheValue { value: self.value } } } @@ -145,7 +172,7 @@ pub trait Storage: Clone { fn with_config(config: Self::RuntimeConfig) -> Result; /// Returns the value corresponding to the key or None if key is absent. - fn get(&self, key: StorageKey, witness: &Self::Witness) -> Option; + fn get(&self, key: &StorageKey, witness: &Self::Witness) -> Option; /// Returns the latest state root hash from the storage. fn get_state_root(&self, witness: &Self::Witness) -> anyhow::Result<[u8; 32]>; @@ -166,18 +193,21 @@ pub trait Storage: Clone { proof: StorageProof, ) -> Result<(StorageKey, Option), anyhow::Error>; - fn verify_proof + StateValueCodec>( + fn verify_proof( &self, state_root: [u8; 32], proof: StorageProof, expected_key: &K, - storage_map: &StateMap, - ) -> Result, anyhow::Error> { + storage_map: &StateMap, + ) -> Result, anyhow::Error> + where + K: Hash + Eq, + { let (storage_key, storage_value) = self.open_proof(state_root, proof)?; // We have to check that the storage key is the same as the external key ensure!( - storage_key == StorageKey::new(storage_map.prefix(), expected_key, &storage_map.codec), + storage_key == StorageKey::new(storage_map.prefix(), expected_key), "The storage key from the proof doesn't match the expected storage key." ); @@ -215,15 +245,15 @@ pub trait NativeStorage: Storage { fn get_with_proof(&self, key: StorageKey, witness: &Self::Witness) -> StorageProof; - fn get_with_proof_from_state_map + StateValueCodec>( + fn get_with_proof_from_state_map( &self, key: &K, - state_map: &StateMap, + state_map: &StateMap, witness: &Self::Witness, - ) -> StorageProof { - self.get_with_proof( - StorageKey::new(state_map.prefix(), key, &state_map.codec), - witness, - ) + ) -> StorageProof + where + K: Hash + Eq, + { + self.get_with_proof(StorageKey::new(state_map.prefix(), key), witness) } } diff --git a/module-system/sov-state/src/value.rs b/module-system/sov-state/src/value.rs index 971071215..89a1bd7cb 100644 --- a/module-system/sov-state/src/value.rs +++ b/module-system/sov-state/src/value.rs @@ -3,14 +3,14 @@ use std::marker::PhantomData; use borsh::{BorshDeserialize, BorshSerialize}; use thiserror::Error; -use crate::codec::{BorshCodec, StateKeyCodec, StateValueCodec}; +use crate::codec::{BorshCodec, StateValueCodec}; use crate::{Prefix, Storage, WorkingSet}; /// Container for a single value. #[derive(Debug, PartialEq, Eq, Clone, BorshDeserialize, BorshSerialize)] -pub struct StateValue { +pub struct StateValue { _phantom: PhantomData, - codec: C, + codec: VC, prefix: Prefix, } @@ -21,27 +21,17 @@ pub enum Error { MissingValue(Prefix), } -impl StateValue -where - BorshCodec: StateValueCodec, -{ +impl StateValue { /// Crates a new [`StateValue`] with the given prefix and the default /// [`StateValueCodec`] (i.e. [`BorshCodec`]). pub fn new(prefix: Prefix) -> Self { - Self { - _phantom: PhantomData, - codec: BorshCodec, - prefix, - } + Self::with_codec(prefix, BorshCodec) } } -impl StateValue -where - C: StateValueCodec, -{ +impl StateValue { /// Creates a new [`StateValue`] with the given prefix and codec. - pub fn with_codec(prefix: Prefix, codec: C) -> Self { + pub fn with_codec(prefix: Prefix, codec: VC) -> Self { Self { _phantom: PhantomData, codec, @@ -53,19 +43,20 @@ where pub fn prefix(&self) -> &Prefix { &self.prefix } +} - fn internal_codec(&self) -> SingletonCodec { - SingletonCodec::new(&self.codec) - } - +impl StateValue +where + VC: StateValueCodec, +{ /// Sets a value in the StateValue. pub fn set(&self, value: &V, working_set: &mut WorkingSet) { - working_set.set_value(self.prefix(), &self.internal_codec(), &SingletonKey, value) + working_set.set_value(self.prefix(), &SingletonKey, value, &self.codec) } /// Gets a value from the StateValue or None if the value is absent. pub fn get(&self, working_set: &mut WorkingSet) -> Option { - working_set.get_value(self.prefix(), &self.internal_codec(), &SingletonKey) + working_set.get_value(self.prefix(), &SingletonKey, &self.codec) } /// Gets a value from the StateValue or Error if the value is absent. @@ -76,7 +67,7 @@ where /// Removes a value from the StateValue, returning the value (or None if the key is absent). pub fn remove(&self, working_set: &mut WorkingSet) -> Option { - working_set.remove_value(self.prefix(), &self.internal_codec(), &SingletonKey) + working_set.remove_value(self.prefix(), &SingletonKey, &self.codec) } /// Removes a value and from the StateValue, returning the value (or Error if the key is absent). @@ -87,55 +78,10 @@ where /// Deletes a value from the StateValue. pub fn delete(&self, working_set: &mut WorkingSet) { - working_set.delete_value(self.prefix(), &self.internal_codec(), &SingletonKey); + working_set.delete_value(self.prefix(), &SingletonKey); } } // SingletonKey is very similar to the unit type `()` i.e. it has only one value. -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq, Hash)] struct SingletonKey; - -/// Skips (de)serialization of keys and delegates values to another codec. -struct SingletonCodec<'a, VC> { - value_codec: &'a VC, -} - -impl<'a, VC> SingletonCodec<'a, VC> { - pub fn new(value_codec: &'a VC) -> Self { - Self { value_codec } - } -} - -impl<'a, VC> StateKeyCodec for SingletonCodec<'a, VC> { - type KeyError = std::io::Error; - - fn encode_key(&self, _: &SingletonKey) -> Vec { - vec![] - } - - fn try_decode_key(&self, bytes: &[u8]) -> Result { - if bytes.is_empty() { - Ok(SingletonKey) - } else { - Err(std::io::Error::new( - std::io::ErrorKind::InvalidData, - "SingletonKey must be empty", - )) - } - } -} - -impl<'a, V, VC> StateValueCodec for SingletonCodec<'a, VC> -where - VC: StateValueCodec, -{ - type ValueError = VC::ValueError; - - fn encode_value(&self, value: &V) -> Vec { - self.value_codec.encode_value(value) - } - - fn try_decode_value(&self, bytes: &[u8]) -> Result { - self.value_codec.try_decode_value(bytes) - } -} diff --git a/module-system/sov-state/src/vec.rs b/module-system/sov-state/src/vec.rs index 8201c761a..894363564 100644 --- a/module-system/sov-state/src/vec.rs +++ b/module-system/sov-state/src/vec.rs @@ -3,11 +3,9 @@ use std::marker::PhantomData; use thiserror::Error; -use crate::codec::{BorshCodec, PairOfCodecs, StateValueCodec}; +use crate::codec::{BorshCodec, StateValueCodec}; use crate::{Prefix, StateMap, StateValue, Storage, WorkingSet}; -type InternalCodec = PairOfCodecs; - #[derive(Debug, Clone)] pub struct StateVec where @@ -16,7 +14,7 @@ where _phantom: PhantomData, prefix: Prefix, len_value: StateValue, - elems: StateMap>, + elems: StateMap, } /// Error type for `StateVec` get method. @@ -50,8 +48,7 @@ where // details of `StateValue` and `StateMap` as they both have the right to // reserve the whole key space for themselves. let len_value = StateValue::::new(prefix.extended(b"l")); - let elems = - StateMap::with_codec(prefix.extended(b"e"), InternalCodec::new(BorshCodec, codec)); + let elems = StateMap::with_codec(prefix.extended(b"e"), codec); Self { _phantom: PhantomData, prefix, diff --git a/module-system/sov-state/src/zk_storage.rs b/module-system/sov-state/src/zk_storage.rs index 9e4ba55ba..7a0140d46 100644 --- a/module-system/sov-state/src/zk_storage.rs +++ b/module-system/sov-state/src/zk_storage.rs @@ -47,7 +47,7 @@ impl Storage for ZkStorage { Ok(Self::new(config)) } - fn get(&self, _key: StorageKey, witness: &Self::Witness) -> Option { + fn get(&self, _key: &StorageKey, witness: &Self::Witness) -> Option { witness.get_hint() }