fuel-core 0.15.3

Fuel client.
Documentation
use crate::{
    database::{
        Column,
        Database,
    },
    state::{
        Error,
        IterDirection,
        MultiKey,
    },
};
use fuel_core_interfaces::{
    common::{
        fuel_storage::{
            StorageInspect,
            StorageMutate,
        },
        fuel_vm::{
            crypto,
            prelude::{
                Bytes32,
                ContractId,
                MerkleRoot,
                MerkleRootStorage,
            },
        },
    },
    db::ContractsState,
};
use itertools::Itertools;
use std::borrow::Cow;

impl StorageInspect<ContractsState<'_>> for Database {
    type Error = Error;

    fn get(&self, key: &(&ContractId, &Bytes32)) -> Result<Option<Cow<Bytes32>>, Error> {
        let key = MultiKey::new(key);
        self.get(key.as_ref(), Column::ContractsState)
            .map_err(Into::into)
    }

    fn contains_key(&self, key: &(&ContractId, &Bytes32)) -> Result<bool, Error> {
        let key = MultiKey::new(key);
        self.exists(key.as_ref(), Column::ContractsState)
            .map_err(Into::into)
    }
}

impl StorageMutate<ContractsState<'_>> for Database {
    fn insert(
        &mut self,
        key: &(&ContractId, &Bytes32),
        value: &Bytes32,
    ) -> Result<Option<Bytes32>, Error> {
        let key = MultiKey::new(key);
        Database::insert(self, key.as_ref(), Column::ContractsState, *value)
            .map_err(Into::into)
    }

    fn remove(
        &mut self,
        key: &(&ContractId, &Bytes32),
    ) -> Result<Option<Bytes32>, Error> {
        let key = MultiKey::new(key);
        Database::remove(self, key.as_ref(), Column::ContractsState).map_err(Into::into)
    }
}

impl MerkleRootStorage<ContractId, ContractsState<'_>> for Database {
    fn root(&mut self, parent: &ContractId) -> Result<MerkleRoot, Error> {
        let items: Vec<_> = Database::iter_all::<Vec<u8>, Bytes32>(
            self,
            Column::ContractsState,
            Some(parent.as_ref().to_vec()),
            None,
            Some(IterDirection::Forward),
        )
        .try_collect()?;

        let root = items
            .iter()
            .filter_map(|(key, value)| {
                (&key[..parent.len()] == parent.as_ref()).then_some((key, value))
            })
            .sorted_by_key(|t| t.0)
            .map(|(_, value)| value);

        Ok(crypto::ephemeral_merkle_root(root).into())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use fuel_core_interfaces::common::fuel_storage::StorageAsMut;

    #[test]
    fn get() {
        let storage_id: (ContractId, Bytes32) =
            (ContractId::from([1u8; 32]), Bytes32::from([1u8; 32]));
        let stored_value: Bytes32 = Bytes32::from([2u8; 32]);
        let key = &(&storage_id.0, &storage_id.1);

        let database = &mut Database::default();
        database
            .storage::<ContractsState>()
            .insert(key, &stored_value)
            .unwrap();

        assert_eq!(
            *database
                .storage::<ContractsState>()
                .get(key)
                .unwrap()
                .unwrap(),
            stored_value
        );
    }

    #[test]
    fn put() {
        let storage_id: (ContractId, Bytes32) =
            (ContractId::from([1u8; 32]), Bytes32::from([1u8; 32]));
        let stored_value: Bytes32 = Bytes32::from([2u8; 32]);
        let key = &(&storage_id.0, &storage_id.1);

        let database = &mut Database::default();
        database
            .storage::<ContractsState>()
            .insert(key, &stored_value)
            .unwrap();

        let returned: Bytes32 = *database
            .storage::<ContractsState>()
            .get(key)
            .unwrap()
            .unwrap();
        assert_eq!(returned, stored_value);
    }

    #[test]
    fn remove() {
        let storage_id: (ContractId, Bytes32) =
            (ContractId::from([1u8; 32]), Bytes32::from([1u8; 32]));
        let stored_value: Bytes32 = Bytes32::from([2u8; 32]);
        let key = &(&storage_id.0, &storage_id.1);

        let database = &mut Database::default();
        database
            .storage::<ContractsState>()
            .insert(key, &stored_value)
            .unwrap();

        database.storage::<ContractsState>().remove(key).unwrap();

        assert!(!database
            .storage::<ContractsState>()
            .contains_key(key)
            .unwrap());
    }

    #[test]
    fn exists() {
        let storage_id: (ContractId, Bytes32) =
            (ContractId::from([1u8; 32]), Bytes32::from([1u8; 32]));
        let stored_value: Bytes32 = Bytes32::from([2u8; 32]);
        let key = &(&storage_id.0, &storage_id.1);

        let database = &mut Database::default();
        database
            .storage::<ContractsState>()
            .insert(key, &stored_value)
            .unwrap();

        assert!(database
            .storage::<ContractsState>()
            .contains_key(key)
            .unwrap());
    }

    #[test]
    fn root() {
        let storage_id: (ContractId, Bytes32) =
            (ContractId::from([1u8; 32]), Bytes32::from([1u8; 32]));
        let stored_value: Bytes32 = Bytes32::from([2u8; 32]);
        let key = &(&storage_id.0, &storage_id.1);

        let database = &mut Database::default();

        database
            .storage::<ContractsState>()
            .insert(key, &stored_value)
            .unwrap();

        let root = database.storage::<ContractsState>().root(&storage_id.0);
        assert!(root.is_ok())
    }
}