use std::fmt::Display;
use std::sync::Arc;
use anyhow::ensure;
use borsh::{BorshDeserialize, BorshSerialize};
use hex;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use sov_first_read_last_write_cache::{CacheKey, CacheValue};
use crate::codec::{EncodeKeyLike, StateKeyCodec, StateValueCodec};
use crate::internal_cache::OrderedReadsAndWrites;
use crate::utils::AlignedVec;
use crate::witness::Witness;
use crate::{Prefix, StateMap};
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize, BorshDeserialize, BorshSerialize)]
pub struct StorageKey {
key: Arc<Vec<u8>>,
}
impl From<CacheKey> for StorageKey {
fn from(cache_key: CacheKey) -> Self {
Self { key: cache_key.key }
}
}
impl StorageKey {
pub fn key(&self) -> Arc<Vec<u8>> {
self.key.clone()
}
pub fn to_cache_key(&self) -> CacheKey {
CacheKey {
key: self.key.clone(),
}
}
pub fn into_cache_key(self) -> CacheKey {
CacheKey { key: self.key }
}
}
impl AsRef<Vec<u8>> for StorageKey {
fn as_ref(&self) -> &Vec<u8> {
&self.key
}
}
impl Display for StorageKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:x?}", hex::encode(self.key().as_ref()))
}
}
impl StorageKey {
pub fn new<K, Q, KC>(prefix: &Prefix, key: &Q, codec: &KC) -> Self
where
KC: EncodeKeyLike<Q, K>,
Q: ?Sized,
{
let encoded_key = codec.encode_key_like(key);
let encoded_key = AlignedVec::new(encoded_key);
let full_key = Vec::<u8>::with_capacity(prefix.len() + encoded_key.len());
let mut full_key = AlignedVec::new(full_key);
full_key.extend(prefix.as_aligned_vec());
full_key.extend(&encoded_key);
Self {
key: Arc::new(full_key.into_inner()),
}
}
pub fn singleton(prefix: &Prefix) -> Self {
Self {
key: Arc::new(prefix.as_aligned_vec().clone().into_inner()),
}
}
}
#[derive(
Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize, Serialize, Deserialize, Default,
)]
pub struct StorageValue {
value: Arc<Vec<u8>>,
}
impl From<CacheValue> for StorageValue {
fn from(cache_value: CacheValue) -> Self {
Self {
value: cache_value.value,
}
}
}
impl From<Vec<u8>> for StorageValue {
fn from(value: Vec<u8>) -> Self {
Self {
value: Arc::new(value),
}
}
}
impl StorageValue {
pub fn new<V, VC>(value: &V, codec: &VC) -> Self
where
VC: StateValueCodec<V>,
{
let encoded_value = codec.encode_value(value);
Self {
value: Arc::new(encoded_value),
}
}
pub fn value(&self) -> &[u8] {
&self.value
}
pub fn into_cache_value(self) -> CacheValue {
CacheValue { value: self.value }
}
}
#[derive(Debug, Clone, Serialize, Deserialize, BorshDeserialize, BorshSerialize)]
pub struct StorageProof<P> {
pub key: StorageKey,
pub value: Option<StorageValue>,
pub proof: P,
}
pub trait Storage: Clone {
type Witness: Witness;
type RuntimeConfig;
type Proof: Serialize
+ DeserializeOwned
+ core::fmt::Debug
+ Clone
+ BorshSerialize
+ BorshDeserialize;
type StateUpdate;
fn with_config(config: Self::RuntimeConfig) -> Result<Self, anyhow::Error>;
fn get(&self, key: &StorageKey, witness: &Self::Witness) -> Option<StorageValue>;
fn get_accessory(&self, _key: &StorageKey) -> Option<StorageValue> {
None
}
fn get_state_root(&self, witness: &Self::Witness) -> anyhow::Result<[u8; 32]>;
fn compute_state_update(
&self,
state_accesses: OrderedReadsAndWrites,
witness: &Self::Witness,
) -> Result<([u8; 32], Self::StateUpdate), anyhow::Error>;
fn commit(&self, node_batch: &Self::StateUpdate, accessory_update: &OrderedReadsAndWrites);
fn validate_and_commit(
&self,
state_accesses: OrderedReadsAndWrites,
witness: &Self::Witness,
) -> Result<[u8; 32], anyhow::Error> {
Self::validate_and_commit_with_accessory_update(
self,
state_accesses,
witness,
&Default::default(),
)
}
fn validate_and_commit_with_accessory_update(
&self,
state_accesses: OrderedReadsAndWrites,
witness: &Self::Witness,
accessory_update: &OrderedReadsAndWrites,
) -> Result<[u8; 32], anyhow::Error> {
let (root_hash, node_batch) = self.compute_state_update(state_accesses, witness)?;
self.commit(&node_batch, accessory_update);
Ok(root_hash)
}
fn open_proof(
&self,
state_root: [u8; 32],
proof: StorageProof<Self::Proof>,
) -> Result<(StorageKey, Option<StorageValue>), anyhow::Error>;
fn verify_proof<K, V, Codec>(
&self,
state_root: [u8; 32],
proof: StorageProof<Self::Proof>,
expected_key: &K,
storage_map: &StateMap<K, V, Codec>,
) -> Result<Option<StorageValue>, anyhow::Error>
where
Codec: StateKeyCodec<K>,
{
let (storage_key, storage_value) = self.open_proof(state_root, proof)?;
ensure!(
storage_key == StorageKey::new(storage_map.prefix(), expected_key, storage_map.codec()),
"The storage key from the proof doesn't match the expected storage key."
);
Ok(storage_value)
}
fn is_empty(&self) -> bool;
}
#[cfg(test)]
impl From<&'static str> for StorageKey {
fn from(key: &'static str) -> Self {
Self {
key: Arc::new(key.as_bytes().to_vec()),
}
}
}
#[cfg(test)]
impl From<&'static str> for StorageValue {
fn from(value: &'static str) -> Self {
Self {
value: Arc::new(value.as_bytes().to_vec()),
}
}
}
pub trait NativeStorage: Storage {
fn get_with_proof(&self, key: StorageKey, witness: &Self::Witness)
-> StorageProof<Self::Proof>;
fn get_with_proof_from_state_map<Q, K, V, Codec>(
&self,
key: &Q,
state_map: &StateMap<K, V, Codec>,
witness: &Self::Witness,
) -> StorageProof<Self::Proof>
where
Codec: EncodeKeyLike<Q, K>,
{
self.get_with_proof(
StorageKey::new(state_map.prefix(), key, state_map.codec()),
witness,
)
}
}