From bedddb5086611bf06514333170cb30a9ac6006ae Mon Sep 17 00:00:00 2001 From: green Date: Fri, 9 Sep 2022 01:54:03 +0100 Subject: [PATCH 1/7] Moved implementation for all tables into `database/storage` folder. Refactored all tables to implement new storage traits(Also refactored all tests). Replaced all `>::method` with `self.storage::().method`. The same for `MerkleRootStorage`. Also refactored all tests. Instead of constants for columns, use the `Column` enum to manage tables columns(Use `Column` everywhere instead of `ColumnId`). In the future, we can use more advanced naming for fields, instead of "column-{i}" because now we have names of enum=) In some places, removed unnecessary usage of `Vec`(in `put`, `insert` etc methods). Removed usage of `Clone` and `Copy` for some `value` in the same methods. Prepared the code for the next refactoring: - to simplify the implementation of storage-related traits - to use only read/write traits in the places where it is really required - performance improvements to work with types more optimal Update stable rust to 1.63 to support enum-iterator --- Cargo.lock | 77 +++- deployment/Dockerfile | 2 +- fuel-core-interfaces/Cargo.toml | 6 +- fuel-core-interfaces/src/db.rs | 83 +++++ fuel-core-interfaces/src/lib.rs | 2 + fuel-core-interfaces/src/relayer.rs | 128 ++++--- fuel-core-interfaces/src/signer.rs | 16 +- fuel-core-interfaces/src/txpool.rs | 28 +- fuel-core-interfaces/src/utils.rs | 16 + fuel-core/Cargo.toml | 1 + fuel-core/src/coin_query.rs | 21 +- fuel-core/src/database.rs | 335 ++++-------------- fuel-core/src/database/balances.rs | 202 ----------- fuel-core/src/database/metadata.rs | 27 +- fuel-core/src/database/relayer.rs | 218 ++++++++++++ fuel-core/src/database/state.rs | 198 ----------- fuel-core/src/database/storage.rs | 61 ++++ fuel-core/src/database/storage/balances.rs | 194 ++++++++++ fuel-core/src/database/{ => storage}/block.rs | 56 +-- .../src/database/{ => storage}/code_root.rs | 112 +++--- fuel-core/src/database/{ => storage}/coin.rs | 58 ++- .../src/database/{ => storage}/contracts.rs | 206 ++++++----- .../database/{ => storage}/delegates_index.rs | 42 ++- .../src/database/{ => storage}/message.rs | 59 +-- .../src/database/{ => storage}/receipts.rs | 34 +- .../database/{ => storage}/staking_diffs.rs | 35 +- fuel-core/src/database/storage/state.rs | 198 +++++++++++ fuel-core/src/database/storage/transaction.rs | 140 ++++++++ .../database/{ => storage}/validator_set.rs | 38 +- fuel-core/src/database/transaction.rs | 134 +------ fuel-core/src/executor.rs | 243 +++++++------ fuel-core/src/schema/balance.rs | 22 +- fuel-core/src/schema/block.rs | 21 +- fuel-core/src/schema/chain.rs | 12 +- fuel-core/src/schema/coin.rs | 10 +- fuel-core/src/schema/contract.rs | 26 +- fuel-core/src/schema/message.rs | 18 +- fuel-core/src/schema/tx.rs | 44 +-- fuel-core/src/schema/tx/types.rs | 22 +- fuel-core/src/service/genesis.rs | 92 ++--- fuel-core/src/state.rs | 32 +- fuel-core/src/state/in_memory.rs | 13 +- fuel-core/src/state/in_memory/memory_store.rs | 40 +-- fuel-core/src/state/in_memory/transaction.rs | 168 ++++----- fuel-core/src/state/rocks_db.rs | 129 ++++--- fuel-core/src/test_utils.rs | 27 +- fuel-relayer/src/mock_db.rs | 109 +++--- fuel-tests/tests/blocks.rs | 16 +- fuel-tests/tests/coin.rs | 31 +- fuel-txpool/src/containers/dependency.rs | 4 +- fuel-txpool/src/mock_db.rs | 78 ++-- fuel-txpool/src/txpool.rs | 217 +++++++----- 52 files changed, 2287 insertions(+), 1814 deletions(-) create mode 100644 fuel-core-interfaces/src/utils.rs delete mode 100644 fuel-core/src/database/balances.rs create mode 100644 fuel-core/src/database/relayer.rs delete mode 100644 fuel-core/src/database/state.rs create mode 100644 fuel-core/src/database/storage.rs create mode 100644 fuel-core/src/database/storage/balances.rs rename fuel-core/src/database/{ => storage}/block.rs (65%) rename fuel-core/src/database/{ => storage}/code_root.rs (54%) rename fuel-core/src/database/{ => storage}/coin.rs (79%) rename fuel-core/src/database/{ => storage}/contracts.rs (59%) rename fuel-core/src/database/{ => storage}/delegates_index.rs (55%) rename fuel-core/src/database/{ => storage}/message.rs (77%) rename fuel-core/src/database/{ => storage}/receipts.rs (51%) rename fuel-core/src/database/{ => storage}/staking_diffs.rs (63%) create mode 100644 fuel-core/src/database/storage/state.rs create mode 100644 fuel-core/src/database/storage/transaction.rs rename fuel-core/src/database/{ => storage}/validator_set.rs (60%) diff --git a/Cargo.lock b/Cargo.lock index 671f0bb2845..7e496e867b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1657,6 +1657,26 @@ dependencies = [ "syn", ] +[[package]] +name = "enum-iterator" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91a4ec26efacf4aeff80887a175a419493cb6f8b5480d26387eb0bd038976187" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "828de45d0ca18782232dfb8f3ea9cc428e8ced380eb26a520baaacfc70de39ce" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "env_logger" version = "0.9.0" @@ -2111,6 +2131,7 @@ dependencies = [ "clap", "derive_more", "dirs", + "enum-iterator", "env_logger", "fuel-block-executor", "fuel-block-importer", @@ -2167,11 +2188,11 @@ dependencies = [ "derive_more", "fuel-asm", "fuel-crypto", - "fuel-merkle", - "fuel-storage", + "fuel-merkle 0.4.0", + "fuel-storage 0.3.0", "fuel-tx", "fuel-types", - "fuel-vm", + "fuel-vm 0.15.0 (git+https://github.com/FuelLabs/fuel-vm?branch=feature/split-storage-trait)", "futures", "lazy_static", "parking_lot 0.12.1", @@ -2208,7 +2229,7 @@ dependencies = [ "derive_more", "fuel-tx", "fuel-types", - "fuel-vm", + "fuel-vm 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures", "hex", "insta", @@ -2227,7 +2248,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fa59f2a4e6cd6d83a51981c5ac706d58fc8ef53700003948c826827b88cfff1" dependencies = [ "digest 0.10.3", - "fuel-storage", + "fuel-storage 0.2.0", + "hashbrown", + "hex", + "sha2 0.10.2", + "thiserror", +] + +[[package]] +name = "fuel-merkle" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c006505ab44132df81c7b38a438a3b8b5ec368b93f9294dcc75ee381c6939655" +dependencies = [ + "digest 0.10.3", + "fuel-storage 0.3.0", "hashbrown", "hex", "sha2 0.10.2", @@ -2305,6 +2340,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34b9161e86d434a93088409530a4f71f42e074b3bbcbb7a27bfe666583f92fd7" +[[package]] +name = "fuel-storage" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0f895423d18472d60eb078cf949608ff3fe6e42e91d41b85993b11528d2c4c3" + [[package]] name = "fuel-sync" version = "0.10.1" @@ -2345,7 +2386,7 @@ checksum = "118b773c25dbf645457fbd9b0288ac923c044d03ce68f492e539c840c3595f5e" dependencies = [ "fuel-asm", "fuel-crypto", - "fuel-merkle", + "fuel-merkle 0.3.0", "fuel-types", "itertools", "num-integer", @@ -2383,12 +2424,32 @@ name = "fuel-vm" version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "516d60fc504570c0ad79f6dffcbd31687b15b76ecf8753bccaeae201baac29d2" +dependencies = [ + "fuel-asm", + "fuel-crypto", + "fuel-merkle 0.3.0", + "fuel-storage 0.2.0", + "fuel-tx", + "fuel-types", + "itertools", + "secp256k1", + "serde", + "sha3", + "tai64", + "thiserror", + "tracing", +] + +[[package]] +name = "fuel-vm" +version = "0.15.0" +source = "git+https://github.com/FuelLabs/fuel-vm?branch=feature/split-storage-trait#06ef9eb4fd60cc5e8021a239cc478ecb608ebc36" dependencies = [ "anyhow", "fuel-asm", "fuel-crypto", - "fuel-merkle", - "fuel-storage", + "fuel-merkle 0.4.0", + "fuel-storage 0.3.0", "fuel-tx", "fuel-types", "itertools", diff --git a/deployment/Dockerfile b/deployment/Dockerfile index 2b61eaf536a..2c6fb557888 100644 --- a/deployment/Dockerfile +++ b/deployment/Dockerfile @@ -1,5 +1,5 @@ # Stage 1: Build -FROM lukemathwalker/cargo-chef:latest-rust-1.61 as chef +FROM lukemathwalker/cargo-chef:latest-rust-1.63 as chef WORKDIR /build/ # hadolint ignore=DL3008 RUN apt-get update && \ diff --git a/fuel-core-interfaces/Cargo.toml b/fuel-core-interfaces/Cargo.toml index 2e30dfc9f25..0ff7bd22c84 100644 --- a/fuel-core-interfaces/Cargo.toml +++ b/fuel-core-interfaces/Cargo.toml @@ -17,11 +17,11 @@ chrono = { version = "0.4" } derive_more = { version = "0.99" } fuel-asm = "0.8" fuel-crypto = { version = "0.6", default-features = false, features = [ "random" ] } -fuel-merkle = { version = "0.3" } -fuel-storage = "0.2" +fuel-merkle = "0.4" +fuel-storage = "0.3" fuel-tx = { version = "0.18", default-features = false } fuel-types = { version = "0.5", default-features = false } -fuel-vm = { version = "0.15", default-features = false } +fuel-vm = { git = "https://github.com/FuelLabs/fuel-vm", branch = "feature/split-storage-trait" } futures = "0.3" lazy_static = "1.4" parking_lot = "0.12" diff --git a/fuel-core-interfaces/src/db.rs b/fuel-core-interfaces/src/db.rs index 2539dcdf91d..fbc40a4e018 100644 --- a/fuel-core-interfaces/src/db.rs +++ b/fuel-core-interfaces/src/db.rs @@ -1,7 +1,90 @@ +use crate::{ + model::{ + Coin, + ConsensusId, + DaBlockHeight, + Message, + ValidatorId, + ValidatorStake, + }, + relayer::StakingDiff, +}; +use fuel_storage::Mappable; +use fuel_tx::{ + Transaction, + UtxoId, +}; +use fuel_types::{ + Address, + Bytes32, + MessageId, +}; use fuel_vm::prelude::InterpreterError; use std::io::ErrorKind; use thiserror::Error; +pub use fuel_vm::storage::{ + ContractsAssets, + ContractsInfo, + ContractsRawCode, + ContractsState, +}; + +/// The storage table of coins UTXOs. +pub struct Coins; + +impl Mappable for Coins { + type Key = UtxoId; + type SetValue = Coin; + type GetValue = Self::SetValue; +} + +/// The storage table of bridget from Ethereum messages. +pub struct Messages; + +impl Mappable for Messages { + type Key = MessageId; + type SetValue = Message; + type GetValue = Self::SetValue; +} + +/// The storage table of confirmed transactions. +pub struct Transactions; + +impl Mappable for Transactions { + type Key = Bytes32; + type SetValue = Transaction; + type GetValue = Self::SetValue; +} + +/// The storage table of delegate's indexes used by relayer. +/// Delegate index maps delegate `Address` with list of da block where delegation happened. +pub struct DelegatesIndexes; + +impl Mappable for DelegatesIndexes { + type Key = Address; + type SetValue = [DaBlockHeight]; + type GetValue = Vec; +} + +/// The storage table of relayer validators set. +pub struct ValidatorsSet; + +impl Mappable for ValidatorsSet { + type Key = ValidatorId; + type SetValue = (ValidatorStake, Option); + type GetValue = Self::SetValue; +} + +/// The storage table of relayer stacking diffs. +pub struct StackingDiffs; + +impl Mappable for StackingDiffs { + type Key = DaBlockHeight; + type SetValue = StakingDiff; + type GetValue = Self::SetValue; +} + #[derive(Error, Debug)] #[non_exhaustive] pub enum Error { diff --git a/fuel-core-interfaces/src/lib.rs b/fuel-core-interfaces/src/lib.rs index b24b163fce1..93215792f68 100644 --- a/fuel-core-interfaces/src/lib.rs +++ b/fuel-core-interfaces/src/lib.rs @@ -8,6 +8,8 @@ pub mod relayer; pub mod signer; pub mod sync; pub mod txpool; +#[cfg(any(test, feature = "test-helpers"))] +pub mod utils; pub mod common { #[doc(no_inline)] diff --git a/fuel-core-interfaces/src/relayer.rs b/fuel-core-interfaces/src/relayer.rs index a7998d9254c..17b18178655 100644 --- a/fuel-core-interfaces/src/relayer.rs +++ b/fuel-core-interfaces/src/relayer.rs @@ -1,13 +1,31 @@ +use crate::{ + db::{ + DelegatesIndexes, + KvStoreError, + Messages, + StackingDiffs, + ValidatorsSet, + }, + model::{ + BlockHeight, + CheckedMessage, + ConsensusId, + DaBlockHeight, + SealedFuelBlock, + ValidatorId, + ValidatorStake, + }, +}; use async_trait::async_trait; use derive_more::{ Deref, DerefMut, }; -use fuel_storage::Storage; -use fuel_types::{ - Address, - MessageId, +use fuel_storage::{ + StorageAsMut, + StorageMutate, }; +use fuel_types::Address; use std::{ collections::HashMap, sync::Arc, @@ -17,6 +35,8 @@ use tokio::sync::{ oneshot, }; +pub use thiserror::Error; + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, Clone)] pub struct StakingDiff { @@ -53,37 +73,45 @@ impl StakingDiff { // But for ValidatorSet, it is little bit different. #[async_trait] pub trait RelayerDb: - Storage // bridge messages - + Storage), Error = KvStoreError> // validator set - + Storage,Error = KvStoreError> // delegate index - + Storage // staking diff + StorageMutate + + StorageMutate + + StorageMutate + + StorageMutate + Send + Sync { - - /// add bridge message to database. Messages are not revertible. - async fn insert_message( - &mut self, - message: &CheckedMessage, - ) { - let _ = Storage::::insert(self,message.id(),message.as_ref()); + /// Add bridge message to database. Messages are not revertible. + async fn insert_message(&mut self, message: &CheckedMessage) { + let _ = self + .storage::() + .insert(message.id(), message.as_ref()); } /// Insert difference make on staking in this particular DA height. - async fn insert_staking_diff(&mut self, da_height: DaBlockHeight, stakes: &StakingDiff) { - let _ = Storage::::insert(self, &da_height,stakes); + async fn insert_staking_diff( + &mut self, + da_height: DaBlockHeight, + stakes: &StakingDiff, + ) { + let _ = self.storage::().insert(&da_height, stakes); } /// Query delegate index to find list of blocks that delegation changed /// iterate over list of indexed to find height that is less but closest to da_height /// Query that block StakeDiff to find actual delegation change. - async fn get_first_lesser_delegation(&mut self,delegate: &Address, da_height: DaBlockHeight) -> Option> { - // get delegate index - let delegate_index = Storage::>::get(self,delegate).expect("Expect to get data without problem")?; + async fn get_first_lesser_delegation( + &mut self, + delegate: &Address, + da_height: DaBlockHeight, + ) -> Option> { + let storage = self.storage::(); + let delegate_index = storage + .get(delegate) + .expect("Expect to get data without problem")?; let mut last_da_height = 0; for index in delegate_index.iter() { - if *index >= da_height { - break; + if *index >= da_height { + break } last_da_height = *index; } @@ -92,37 +120,52 @@ pub trait RelayerDb: return None } // get staking diff - let staking_diff = Storage::::get(self, &last_da_height).expect("Expect to get data without problem")?; + let storage = self.storage::(); + let staking_diff = storage + .get(&last_da_height) + .expect("Expect to get data without problem")?; staking_diff.delegations.get(delegate).unwrap().clone() } - async fn append_delegate_index(&mut self, delegate: &Address, da_height: DaBlockHeight) { - let new_indexes = if let Some(indexes) = Storage::>::get(self,delegate).unwrap() { + async fn append_delegate_index( + &mut self, + delegate: &Address, + da_height: DaBlockHeight, + ) { + let new_indexes = if let Some(indexes) = + self.storage::().get(delegate).unwrap() + { let mut indexes = (*indexes).clone(); indexes.push(da_height); indexes } else { vec![da_height] }; - Storage::>::insert(self,delegate,&new_indexes).expect("Expect to insert without problem"); + self.storage::() + .insert(delegate, &new_indexes) + .expect("Expect to insert without problem"); } /// get stakes difference between fuel blocks. Return vector of changed (some blocks are not going to have any change) async fn get_staking_diffs( - &self, - _from_da_height: DaBlockHeight, - _to_da_height: Option, + &self, + _from_da_height: DaBlockHeight, + _to_da_height: Option, ) -> Vec<(DaBlockHeight, StakingDiff)> { Vec::new() } /// Apply validators diff to validator set and update validators_da_height. This operation needs /// to be atomic. - async fn apply_validator_diffs(&mut self, da_height: DaBlockHeight, changes: &HashMap)>) { + async fn apply_validator_diffs( + &mut self, + da_height: DaBlockHeight, + changes: &HashMap)>, + ) { // this is reimplemented inside fuel-core db to assure it is atomic operation in case of poweroff situation - for ( address, stake) in changes { - let _ = Storage::)>::insert(self,address,stake); + for (address, stake) in changes { + let _ = self.storage::().insert(address, stake); } self.set_validators_da_height(da_height).await; } @@ -130,7 +173,8 @@ pub trait RelayerDb: /// current best block number async fn get_chain_height(&self) -> BlockHeight; - async fn get_sealed_block(&self, height: BlockHeight) -> Option>; + async fn get_sealed_block(&self, height: BlockHeight) + -> Option>; /// get validator set for current eth height async fn get_validators(&self) -> ValidatorSet; @@ -153,7 +197,7 @@ pub trait RelayerDb: async fn get_last_committed_finalized_fuel_height(&self) -> BlockHeight; /// Set last committed finalized fuel height this means we are safe to remove consensus votes from db - /// as from this moment they are not needed any more + /// as from this moment they are not needed any more async fn set_last_committed_finalized_fuel_height(&self, block_height: BlockHeight); } @@ -220,22 +264,6 @@ impl Sender { } } -pub use thiserror::Error; - -use crate::{ - db::KvStoreError, - model::{ - BlockHeight, - CheckedMessage, - ConsensusId, - DaBlockHeight, - Message, - SealedFuelBlock, - ValidatorId, - ValidatorStake, - }, -}; - #[derive(Error, Debug, PartialEq, Eq, Copy, Clone)] pub enum RelayerError { #[error("Temp stopped")] diff --git a/fuel-core-interfaces/src/signer.rs b/fuel-core-interfaces/src/signer.rs index a659b58842a..b910e997c4e 100644 --- a/fuel-core-interfaces/src/signer.rs +++ b/fuel-core-interfaces/src/signer.rs @@ -3,7 +3,7 @@ use fuel_types::Bytes32; use thiserror::Error; /// Dummy signer that will be removed in next pull request. -/// TODO do not use. +/// TODO: Do not use. #[async_trait] pub trait Signer { async fn sign(&self, hash: &Bytes32) -> Result; @@ -14,17 +14,3 @@ pub enum SignerError { #[error("Private key not loaded")] KeyNotLoaded, } - -#[cfg(any(test, feature = "test-helpers"))] -pub mod helpers { - use super::*; - - pub struct DummySigner {} - - #[async_trait] - impl Signer for DummySigner { - async fn sign(&self, hash: &Bytes32) -> Result { - Ok(*hash) - } - } -} diff --git a/fuel-core-interfaces/src/txpool.rs b/fuel-core-interfaces/src/txpool.rs index 3ad6a3953b4..4d520dbd078 100644 --- a/fuel-core-interfaces/src/txpool.rs +++ b/fuel-core-interfaces/src/txpool.rs @@ -1,7 +1,9 @@ use crate::{ db::{ + Coins, Error as DbStateError, KvStoreError, + Messages, }, model::{ ArcTx, @@ -14,7 +16,10 @@ use derive_more::{ Deref, DerefMut, }; -use fuel_storage::Storage; +use fuel_storage::{ + StorageAsRef, + StorageInspect, +}; use fuel_tx::{ ContractId, Transaction, @@ -22,7 +27,7 @@ use fuel_tx::{ UtxoId, }; use fuel_types::MessageId; -use fuel_vm::prelude::Contract; +use fuel_vm::storage::ContractsRawCode; use std::sync::Arc; use thiserror::Error; use tokio::sync::{ @@ -31,22 +36,25 @@ use tokio::sync::{ }; pub trait TxPoolDb: - Storage - + Storage - + Storage + StorageInspect + + StorageInspect + + StorageInspect + Send + Sync { fn utxo(&self, utxo_id: &UtxoId) -> Result, KvStoreError> { - Storage::::get(self, utxo_id).map(|t| t.map(|t| t.as_ref().clone())) + self.storage::() + .get(utxo_id) + .map(|t| t.map(|t| t.as_ref().clone())) } - fn contract_exist(&self, contract_id: ContractId) -> Result { - Storage::::contains_key(self, &contract_id) + fn contract_exist(&self, contract_id: &ContractId) -> Result { + self.storage::().contains_key(contract_id) } - fn message(&self, message_id: MessageId) -> Result, KvStoreError> { - Storage::::get(self, &message_id) + fn message(&self, message_id: &MessageId) -> Result, KvStoreError> { + self.storage::() + .get(message_id) .map(|t| t.map(|t| t.as_ref().clone())) } } diff --git a/fuel-core-interfaces/src/utils.rs b/fuel-core-interfaces/src/utils.rs new file mode 100644 index 00000000000..84300ffb53a --- /dev/null +++ b/fuel-core-interfaces/src/utils.rs @@ -0,0 +1,16 @@ +pub mod signer { + use crate::signer::{ + Signer, + SignerError, + }; + use fuel_types::Bytes32; + + pub struct DummySigner {} + + #[async_trait::async_trait] + impl Signer for DummySigner { + async fn sign(&self, hash: &Bytes32) -> Result { + Ok(*hash) + } + } +} diff --git a/fuel-core/Cargo.toml b/fuel-core/Cargo.toml index 1144042ad92..1686e573fa4 100644 --- a/fuel-core/Cargo.toml +++ b/fuel-core/Cargo.toml @@ -32,6 +32,7 @@ chrono = { version = "0.4", features = ["serde"] } clap = { version = "3.2", features = ["env", "derive"] } derive_more = { version = "0.99" } dirs = "3.0" +enum-iterator = "1.2" env_logger = "0.9" fuel-block-executor = { path = "../fuel-block-executor", version = "0.10.1" } fuel-block-importer = { path = "../fuel-block-importer", version = "0.10.1" } diff --git a/fuel-core/src/coin_query.rs b/fuel-core/src/coin_query.rs index ddeaacf2283..0e9c5ca369a 100644 --- a/fuel-core/src/coin_query.rs +++ b/fuel-core/src/coin_query.rs @@ -9,13 +9,16 @@ use crate::{ }, state::{self,}, }; -use fuel_core_interfaces::common::{ - fuel_storage::Storage, - fuel_tx::{ - Address, - AssetId, - UtxoId, +use fuel_core_interfaces::{ + common::{ + fuel_storage::StorageAsRef, + fuel_tx::{ + Address, + AssetId, + UtxoId, + }, }, + db::Coins, }; use itertools::Itertools; use rand::prelude::*; @@ -88,7 +91,8 @@ pub fn largest_first( let mut coins: Vec<(UtxoId, Coin)> = coin_ids .into_iter() .map(|id| { - Storage::::get(db, &id) + db.storage::() + .get(&id) .transpose() .ok_or(KvStoreError::NotFound)? .map(|coin| (id, coin.into_owned())) @@ -168,7 +172,8 @@ pub fn random_improve( let coins: Vec<(UtxoId, Coin)> = coin_ids .into_iter() .map(|id| { - Storage::::get(db, &id) + db.storage::() + .get(&id) .transpose() .ok_or(KvStoreError::NotFound)? .map(|coin| (id, coin.into_owned())) diff --git a/fuel-core/src/database.rs b/fuel-core/src/database.rs index f07a45ed88d..701038558d8 100644 --- a/fuel-core/src/database.rs +++ b/fuel-core/src/database.rs @@ -1,13 +1,10 @@ -#[cfg(feature = "rocksdb")] -use crate::database::columns::COLUMN_NUM; -#[cfg(feature = "rocksdb")] -use crate::state::rocks_db::RocksDb; use crate::{ - database::transactional::DatabaseTransaction, - model::FuelBlockDb, + database::{ + storage::FuelBlocks, + transactional::DatabaseTransaction, + }, state::{ in_memory::memory_store::MemoryStore, - ColumnId, DataSource, Error, IterDirection, @@ -18,7 +15,7 @@ pub use fuel_core_interfaces::db::KvStoreError; use fuel_core_interfaces::{ common::{ fuel_asm::Word, - fuel_storage::Storage, + fuel_storage::StorageAsRef, fuel_vm::prelude::{ Address, Bytes32, @@ -27,88 +24,72 @@ use fuel_core_interfaces::{ }, model::{ BlockHeight, - ConsensusId, - DaBlockHeight, SealedFuelBlock, - ValidatorId, - ValidatorStake, }, p2p::P2pDb, - relayer::{ - RelayerDb, - StakingDiff, - }, + relayer::RelayerDb, txpool::TxPoolDb, }; use serde::{ de::DeserializeOwned, Serialize, }; -#[cfg(feature = "rocksdb")] -use std::path::Path; use std::{ - collections::HashMap, fmt::{ self, Debug, Formatter, }, marker::Send, - ops::DerefMut, sync::Arc, }; + +#[cfg(feature = "rocksdb")] +use crate::state::rocks_db::RocksDb; +#[cfg(feature = "rocksdb")] +use std::path::Path; #[cfg(feature = "rocksdb")] use tempfile::TempDir; -use self::columns::METADATA; - -pub mod balances; -pub mod block; -pub mod code_root; -pub mod coin; -pub mod contracts; -pub mod delegates_index; -pub mod message; pub mod metadata; -mod receipts; -pub mod staking_diffs; -pub mod state; +mod relayer; +pub mod storage; pub mod transaction; pub mod transactional; -pub mod validator_set; - -pub mod columns { - pub const METADATA: u32 = 0; - pub const CONTRACTS: u32 = 1; - pub const CONTRACTS_CODE_ROOT: u32 = 2; - pub const CONTRACTS_STATE: u32 = 3; - // Contract Id -> Utxo Id - pub const CONTRACT_UTXO_ID: u32 = 4; - pub const BALANCES: u32 = 5; - pub const COIN: u32 = 6; - // (owner, coin id) => true - pub const OWNED_COINS: u32 = 7; - pub const TRANSACTIONS: u32 = 8; - // tx id -> current status - pub const TRANSACTION_STATUS: u32 = 9; - pub const TRANSACTIONS_BY_OWNER_BLOCK_IDX: u32 = 10; - pub const RECEIPTS: u32 = 11; - pub const BLOCKS: u32 = 12; - // maps block id -> block hash - pub const BLOCK_IDS: u32 = 13; - pub const MESSAGES: u32 = 14; - /// contain current validator stake and it consensus_key if set. - pub const VALIDATOR_SET: u32 = 15; - /// contain diff between da blocks it contains new registers consensus key and new delegate sets. - pub const STAKING_DIFFS: u32 = 16; - /// Maps delegate address with validator_set_diff index where last delegate change happened - pub const DELEGATES_INDEX: u32 = 17; - // (Owner, MessageId) => true - pub const OWNED_MESSAGE_IDS: u32 = 18; - // Number of columns - #[cfg(feature = "rocksdb")] - pub const COLUMN_NUM: u32 = 19; +/// Database tables column ids. +#[repr(u32)] +#[derive( + Copy, Clone, Debug, strum_macros::EnumCount, PartialEq, Eq, enum_iterator::Sequence, +)] +pub enum Column { + Metadata = 0, + ContractsRawCode = 1, + ContractsInfo = 2, + ContractsState = 3, + /// Contract Id -> Utxo Id + ContractUtxoId = 4, + Balances = 5, + Coins = 6, + /// (owner, coin id) => true + OwnedCoins = 7, + Transaction = 8, + /// tx id -> current status + TransactionStatus = 9, + TransactionsByOwnerBlockIdx = 10, + Receipts = 11, + Blocks = 12, + /// maps block id -> block hash + BlockIds = 13, + Messages = 14, + /// Contain current validator stake and it consensus_key if set. + ValidatorSet = 15, + /// Contain diff between da blocks it contains new registers consensus key and new delegate sets. + StackingDiffs = 16, + /// Maps delegate address with validator_set_diff index where last delegate change happened. + DelegatesIndex = 17, + /// (Owner, MessageId) => true + OwnedMessageIds = 18, } #[derive(Clone, Debug)] @@ -155,21 +136,10 @@ impl Drop for DropResources { unsafe impl Send for Database {} unsafe impl Sync for Database {} -impl TxPoolDb for Database {} -#[async_trait] -impl P2pDb for Database { - async fn get_sealed_block( - &self, - height: BlockHeight, - ) -> Option> { - ::get_sealed_block(self, height).await - } -} - impl Database { #[cfg(feature = "rocksdb")] pub fn open(path: &Path) -> Result { - let db = RocksDb::open(path, COLUMN_NUM)?; + let db = RocksDb::default_open(path)?; Ok(Database { data: Arc::new(db), @@ -184,14 +154,14 @@ impl Database { } } - fn insert>, V: Serialize + DeserializeOwned>( + fn insert, V: Serialize, R: DeserializeOwned>( &self, key: K, - column: ColumnId, + column: Column, value: V, - ) -> Result, Error> { + ) -> Result, Error> { let result = self.data.put( - key.into(), + key.as_ref(), column, bincode::serialize(&value).map_err(|_| Error::Codec)?, )?; @@ -207,7 +177,7 @@ impl Database { fn remove( &self, key: &[u8], - column: ColumnId, + column: Column, ) -> Result, Error> { self.data .delete(key, column)? @@ -218,7 +188,7 @@ impl Database { fn get( &self, key: &[u8], - column: ColumnId, + column: Column, ) -> Result, Error> { self.data .get(key, column)? @@ -226,13 +196,13 @@ impl Database { .transpose() } - fn exists(&self, key: &[u8], column: ColumnId) -> Result { + fn exists(&self, key: &[u8], column: Column) -> Result { self.data.exists(key, column) } fn iter_all( &self, - column: ColumnId, + column: Column, prefix: Option>, start: Option>, direction: Option, @@ -280,9 +250,7 @@ impl Default for Database { { let tmp_dir = TempDir::new().unwrap(); Self { - data: Arc::new( - RocksDb::open(tmp_dir.path(), columns::COLUMN_NUM).unwrap(), - ), + data: Arc::new(RocksDb::default_open(tmp_dir.path()).unwrap()), _drop: Arc::new( { move || { @@ -307,7 +275,7 @@ impl InterpreterStorage for Database { fn timestamp(&self, height: u32) -> Result { let id = self.block_hash(height)?; - let block = Storage::::get(self, &id)?.unwrap_or_default(); + let block = self.storage::().get(&id)?.unwrap_or_default(); block .headers .time @@ -324,196 +292,19 @@ impl InterpreterStorage for Database { fn coinbase(&self) -> Result { let height = self.get_block_height()?.unwrap_or_default(); let id = self.block_hash(height.into())?; - let block = Storage::::get(self, &id)?.unwrap_or_default(); + let block = self.storage::().get(&id)?.unwrap_or_default(); Ok(block.headers.producer) } } -#[async_trait] -impl RelayerDb for Database { - async fn get_validators( - &self, - ) -> HashMap)> { - struct WrapAddress(pub ValidatorId); - impl From> for WrapAddress { - fn from(i: Vec) -> Self { - Self(ValidatorId::try_from(i.as_ref()).unwrap()) - } - } - let mut out = HashMap::new(); - for diff in self.iter_all::)>( - columns::VALIDATOR_SET, - None, - None, - None, - ) { - match diff { - Ok((address, stake)) => { - out.insert(address.0, stake); - } - Err(err) => panic!("Database internal error:{:?}", err), - } - } - out - } - - async fn get_staking_diffs( - &self, - from_da_height: DaBlockHeight, - to_da_height: Option, - ) -> Vec<(DaBlockHeight, StakingDiff)> { - let to_da_height = if let Some(to_da_height) = to_da_height { - if from_da_height > to_da_height { - return Vec::new() - } - to_da_height - } else { - DaBlockHeight::MAX - }; - struct WrapU64Be(pub DaBlockHeight); - impl From> for WrapU64Be { - fn from(i: Vec) -> Self { - use byteorder::{ - BigEndian, - ReadBytesExt, - }; - use std::io::Cursor; - let mut i = Cursor::new(i); - Self(i.read_u64::().unwrap_or_default()) - } - } - let mut out = Vec::new(); - for diff in self.iter_all::( - columns::STAKING_DIFFS, - None, - Some(from_da_height.to_be_bytes().to_vec()), - None, - ) { - match diff { - Ok((key, diff)) => { - let block = key.0; - if block > to_da_height { - return out - } - out.push((block, diff)) - } - Err(err) => panic!("get_validator_diffs unexpected error:{:?}", err), - } - } - out - } - - async fn apply_validator_diffs( - &mut self, - da_height: DaBlockHeight, - changes: &HashMap)>, - ) { - // this is reimplemented here to assure it is atomic operation in case of poweroff situation. - let mut db = self.transaction(); - // TODO - for (address, stake) in changes { - let _ = Storage::)>::insert( - db.deref_mut(), - address, - stake, - ); - } - db.set_validators_da_height(da_height).await; - if let Err(err) = db.commit() { - panic!("apply_validator_diffs database corrupted: {:?}", err); - } - } - - async fn get_chain_height(&self) -> BlockHeight { - match self.get_block_height() { - Ok(res) => { - res.expect("get_block_height value should be always present and set") - } - Err(err) => { - panic!("get_block_height database corruption, err:{:?}", err); - } - } - } +impl TxPoolDb for Database {} +#[async_trait] +impl P2pDb for Database { async fn get_sealed_block( &self, - _height: BlockHeight, + height: BlockHeight, ) -> Option> { - // TODO - Some(Arc::new(SealedFuelBlock::default())) - } - - async fn set_finalized_da_height(&self, block: DaBlockHeight) { - if let Err(err) = self.insert(metadata::FINALIZED_DA_HEIGHT_KEY, METADATA, block) - { - panic!("set_finalized_da_height should always succeed: {:?}", err); - } - } - - async fn get_finalized_da_height(&self) -> DaBlockHeight { - match self.get(metadata::FINALIZED_DA_HEIGHT_KEY, METADATA) { - Ok(res) => { - return res.expect( - "get_finalized_da_height value should be always present and set", - ) - } - Err(err) => { - panic!("get_finalized_da_height database corruption, err:{:?}", err); - } - } - } - - async fn set_validators_da_height(&self, block: DaBlockHeight) { - if let Err(err) = self.insert(metadata::VALIDATORS_DA_HEIGHT_KEY, METADATA, block) - { - panic!("set_validators_da_height should always succeed: {:?}", err); - } - } - - async fn get_validators_da_height(&self) -> DaBlockHeight { - match self.get(metadata::VALIDATORS_DA_HEIGHT_KEY, METADATA) { - Ok(res) => { - return res.expect( - "get_validators_da_height value should be always present and set", - ) - } - Err(err) => { - panic!( - "get_validators_da_height database corruption, err:{:?}", - err - ); - } - } - } - - async fn get_last_committed_finalized_fuel_height(&self) -> BlockHeight { - match self.get( - metadata::LAST_COMMITTED_FINALIZED_BLOCK_HEIGHT_KEY, - METADATA, - ) { - Ok(res) => { - return res - .expect("set_last_committed_finalized_fuel_height value should be always present and set"); - } - Err(err) => { - panic!( - "set_last_committed_finalized_fuel_height database corruption, err:{:?}", - err - ); - } - } - } - - async fn set_last_committed_finalized_fuel_height(&self, block_height: BlockHeight) { - if let Err(err) = self.insert( - metadata::LAST_COMMITTED_FINALIZED_BLOCK_HEIGHT_KEY, - METADATA, - block_height, - ) { - panic!( - "set_last_committed_finalized_fuel_height should always succeed: {:?}", - err - ); - } + ::get_sealed_block(self, height).await } } diff --git a/fuel-core/src/database/balances.rs b/fuel-core/src/database/balances.rs deleted file mode 100644 index c2abdea1b59..00000000000 --- a/fuel-core/src/database/balances.rs +++ /dev/null @@ -1,202 +0,0 @@ -use crate::{ - database::{ - columns::BALANCES, - Database, - }, - state::{ - Error, - IterDirection, - MultiKey, - }, -}; -use fuel_core_interfaces::common::{ - fuel_storage::MerkleRoot, - fuel_vm::{ - crypto, - prelude::{ - AssetId, - ContractId, - MerkleStorage, - Word, - }, - }, -}; -use itertools::Itertools; -use std::borrow::Cow; - -impl MerkleStorage for Database { - type Error = Error; - - fn insert( - &mut self, - parent: &ContractId, - key: &AssetId, - value: &Word, - ) -> Result, Error> { - let key = MultiKey::new((parent, key)); - Database::insert(self, key.as_ref().to_vec(), BALANCES, *value) - } - - fn remove( - &mut self, - parent: &ContractId, - key: &AssetId, - ) -> Result, Error> { - let key = MultiKey::new((parent, key)); - Database::remove(self, key.as_ref(), BALANCES) - } - - fn get( - &self, - parent: &ContractId, - key: &AssetId, - ) -> Result>, Error> { - let key = MultiKey::new((parent, key)); - self.get(key.as_ref(), BALANCES) - } - - fn contains_key(&self, parent: &ContractId, key: &AssetId) -> Result { - let key = MultiKey::new((parent, key)); - self.exists(key.as_ref(), BALANCES) - } - - fn root(&mut self, parent: &ContractId) -> Result { - let items: Vec<_> = Database::iter_all::, Word>( - self, - BALANCES, - 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(|| (key, value)) - }) - .sorted_by_key(|t| t.0) - .map(|(_, value)| value.to_be_bytes()); - - Ok(crypto::ephemeral_merkle_root(root).into()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn get() { - let balance_id: (ContractId, AssetId) = - (ContractId::from([1u8; 32]), AssetId::new([1u8; 32])); - let balance: Word = 100; - - let database = Database::default(); - let key: Vec = MultiKey::new(balance_id).into(); - let _: Option = database.insert(key, BALANCES, balance).unwrap(); - - assert_eq!( - MerkleStorage::::get( - &database, - &balance_id.0, - &balance_id.1 - ) - .unwrap() - .unwrap() - .into_owned(), - balance - ); - } - - #[test] - fn put() { - let balance_id: (ContractId, AssetId) = - (ContractId::from([1u8; 32]), AssetId::new([1u8; 32])); - let balance: Word = 100; - - let mut database = Database::default(); - MerkleStorage::::insert( - &mut database, - &balance_id.0, - &balance_id.1, - &balance, - ) - .unwrap(); - - let returned: Word = database - .get(MultiKey::new(balance_id).as_ref(), BALANCES) - .unwrap() - .unwrap(); - assert_eq!(returned, balance); - } - - #[test] - fn remove() { - let balance_id: (ContractId, AssetId) = - (ContractId::from([1u8; 32]), AssetId::new([1u8; 32])); - let balance: Word = 100; - - let mut database = Database::default(); - database - .insert(MultiKey::new(balance_id), BALANCES, balance) - .unwrap(); - - MerkleStorage::::remove( - &mut database, - &balance_id.0, - &balance_id.1, - ) - .unwrap(); - - assert!(!database - .exists(MultiKey::new(balance_id).as_ref(), BALANCES) - .unwrap()); - } - - #[test] - fn exists() { - let balance_id: (ContractId, AssetId) = - (ContractId::from([1u8; 32]), AssetId::new([1u8; 32])); - let balance: Word = 100; - - let database = Database::default(); - database - .insert( - MultiKey::new(balance_id).as_ref().to_vec(), - BALANCES, - balance, - ) - .unwrap(); - - assert!(MerkleStorage::::contains_key( - &database, - &balance_id.0, - &balance_id.1 - ) - .unwrap()); - } - - #[test] - fn root() { - let balance_id: (ContractId, AssetId) = - (ContractId::from([1u8; 32]), AssetId::new([1u8; 32])); - let balance: Word = 100; - - let mut database = Database::default(); - - MerkleStorage::::insert( - &mut database, - &balance_id.0, - &balance_id.1, - &balance, - ) - .unwrap(); - - let root = MerkleStorage::::root( - &mut database, - &balance_id.0, - ); - assert!(root.is_ok()) - } -} diff --git a/fuel-core/src/database/metadata.rs b/fuel-core/src/database/metadata.rs index 21d61bcabcd..da78506feae 100644 --- a/fuel-core/src/database/metadata.rs +++ b/fuel-core/src/database/metadata.rs @@ -1,6 +1,6 @@ use crate::{ database::{ - columns::METADATA, + Column, Database, }, model::BlockHeight, @@ -24,10 +24,10 @@ impl Database { // check only for one field if it initialized or not. self.insert( CHAIN_NAME_KEY, - METADATA, + Column::Metadata, config.chain_conf.chain_name.clone(), ) - .and_then(|v| { + .and_then(|v: Option| { if v.is_some() { Err(Error::ChainAlreadyInitialized) } else { @@ -42,19 +42,26 @@ impl Database { .and_then(|c| c.height) .unwrap_or_default(); - self.insert(DB_VERSION_KEY, METADATA, DB_VERSION)?; - self.insert(CHAIN_HEIGHT_KEY, METADATA, chain_height)?; - self.insert(FINALIZED_DA_HEIGHT_KEY, METADATA, 0)?; - self.insert(VALIDATORS_DA_HEIGHT_KEY, METADATA, 0)?; - self.insert(LAST_COMMITTED_FINALIZED_BLOCK_HEIGHT_KEY, METADATA, 0)?; + let _: Option = self.insert(DB_VERSION_KEY, Column::Metadata, DB_VERSION)?; + let _: Option = + self.insert(CHAIN_HEIGHT_KEY, Column::Metadata, chain_height)?; + let _: Option = + self.insert(FINALIZED_DA_HEIGHT_KEY, Column::Metadata, 0)?; + let _: Option = + self.insert(VALIDATORS_DA_HEIGHT_KEY, Column::Metadata, 0)?; + let _: Option = self.insert( + LAST_COMMITTED_FINALIZED_BLOCK_HEIGHT_KEY, + Column::Metadata, + 0, + )?; Ok(()) } pub fn get_chain_name(&self) -> Result, Error> { - self.get(CHAIN_NAME_KEY, METADATA) + self.get(CHAIN_NAME_KEY, Column::Metadata) } pub fn get_starting_chain_height(&self) -> Result, Error> { - self.get(CHAIN_HEIGHT_KEY, METADATA) + self.get(CHAIN_HEIGHT_KEY, Column::Metadata) } } diff --git a/fuel-core/src/database/relayer.rs b/fuel-core/src/database/relayer.rs new file mode 100644 index 00000000000..04426cfb34c --- /dev/null +++ b/fuel-core/src/database/relayer.rs @@ -0,0 +1,218 @@ +use crate::database::{ + metadata, + Column, + Database, +}; +use fuel_core_interfaces::{ + common::fuel_storage::StorageAsMut, + db::ValidatorsSet, + model::{ + BlockHeight, + ConsensusId, + DaBlockHeight, + SealedFuelBlock, + ValidatorId, + ValidatorStake, + }, + relayer::{ + RelayerDb, + StakingDiff, + }, +}; +use std::{ + collections::HashMap, + ops::DerefMut, + sync::Arc, +}; + +#[async_trait::async_trait] +impl RelayerDb for Database { + async fn get_validators( + &self, + ) -> HashMap)> { + struct WrapAddress(pub ValidatorId); + impl From> for WrapAddress { + fn from(i: Vec) -> Self { + Self(ValidatorId::try_from(i.as_ref()).unwrap()) + } + } + let mut out = HashMap::new(); + for diff in self.iter_all::)>( + Column::ValidatorSet, + None, + None, + None, + ) { + match diff { + Ok((address, stake)) => { + out.insert(address.0, stake); + } + Err(err) => panic!("Database internal error:{:?}", err), + } + } + out + } + + async fn get_staking_diffs( + &self, + from_da_height: DaBlockHeight, + to_da_height: Option, + ) -> Vec<(DaBlockHeight, StakingDiff)> { + let to_da_height = if let Some(to_da_height) = to_da_height { + if from_da_height > to_da_height { + return Vec::new() + } + to_da_height + } else { + DaBlockHeight::MAX + }; + struct WrapU64Be(pub DaBlockHeight); + impl From> for WrapU64Be { + fn from(i: Vec) -> Self { + use byteorder::{ + BigEndian, + ReadBytesExt, + }; + use std::io::Cursor; + let mut i = Cursor::new(i); + Self(i.read_u64::().unwrap_or_default()) + } + } + let mut out = Vec::new(); + for diff in self.iter_all::( + Column::StackingDiffs, + None, + Some(from_da_height.to_be_bytes().to_vec()), + None, + ) { + match diff { + Ok((key, diff)) => { + let block = key.0; + if block > to_da_height { + return out + } + out.push((block, diff)) + } + Err(err) => panic!("get_validator_diffs unexpected error:{:?}", err), + } + } + out + } + + async fn apply_validator_diffs( + &mut self, + da_height: DaBlockHeight, + changes: &HashMap)>, + ) { + // this is reimplemented here to assure it is atomic operation in case of poweroff situation. + let mut db = self.transaction(); + // TODO + for (address, stake) in changes { + let _ = db + .deref_mut() + .storage::() + .insert(address, stake); + } + db.set_validators_da_height(da_height).await; + if let Err(err) = db.commit() { + panic!("apply_validator_diffs database corrupted: {:?}", err); + } + } + + async fn get_chain_height(&self) -> BlockHeight { + match self.get_block_height() { + Ok(res) => { + res.expect("get_block_height value should be always present and set") + } + Err(err) => { + panic!("get_block_height database corruption, err:{:?}", err); + } + } + } + + async fn get_sealed_block( + &self, + _height: BlockHeight, + ) -> Option> { + // TODO + Some(Arc::new(SealedFuelBlock::default())) + } + + async fn set_finalized_da_height(&self, block: DaBlockHeight) { + let _: Option = self + .insert(metadata::FINALIZED_DA_HEIGHT_KEY, Column::Metadata, block) + .unwrap_or_else(|err| { + panic!("set_finalized_da_height should always succeed: {:?}", err); + }); + } + + async fn get_finalized_da_height(&self) -> DaBlockHeight { + match self.get(metadata::FINALIZED_DA_HEIGHT_KEY, Column::Metadata) { + Ok(res) => { + return res.expect( + "get_finalized_da_height value should be always present and set", + ) + } + Err(err) => { + panic!("get_finalized_da_height database corruption, err:{:?}", err); + } + } + } + + async fn set_validators_da_height(&self, block: DaBlockHeight) { + let _: Option = self + .insert(metadata::VALIDATORS_DA_HEIGHT_KEY, Column::Metadata, block) + .unwrap_or_else(|err| { + panic!("set_validators_da_height should always succeed: {:?}", err); + }); + } + + async fn get_validators_da_height(&self) -> DaBlockHeight { + match self.get(metadata::VALIDATORS_DA_HEIGHT_KEY, Column::Metadata) { + Ok(res) => { + return res.expect( + "get_validators_da_height value should be always present and set", + ) + } + Err(err) => { + panic!( + "get_validators_da_height database corruption, err:{:?}", + err + ); + } + } + } + + async fn get_last_committed_finalized_fuel_height(&self) -> BlockHeight { + match self.get( + metadata::LAST_COMMITTED_FINALIZED_BLOCK_HEIGHT_KEY, + Column::Metadata, + ) { + Ok(res) => { + return res + .expect("set_last_committed_finalized_fuel_height value should be always present and set"); + } + Err(err) => { + panic!( + "set_last_committed_finalized_fuel_height database corruption, err:{:?}", + err + ); + } + } + } + + async fn set_last_committed_finalized_fuel_height(&self, block_height: BlockHeight) { + let _: Option = self + .insert( + metadata::LAST_COMMITTED_FINALIZED_BLOCK_HEIGHT_KEY, + Column::Metadata, + block_height, + ) + .unwrap_or_else(|err| { + panic!( + "set_last_committed_finalized_fuel_height should always succeed: {:?}", + err + ); + }); + } +} diff --git a/fuel-core/src/database/state.rs b/fuel-core/src/database/state.rs deleted file mode 100644 index a41d3accd08..00000000000 --- a/fuel-core/src/database/state.rs +++ /dev/null @@ -1,198 +0,0 @@ -use crate::{ - database::{ - columns::CONTRACTS_STATE, - Database, - }, - state::{ - Error, - IterDirection, - MultiKey, - }, -}; -use fuel_core_interfaces::common::fuel_vm::{ - crypto, - prelude::{ - Bytes32, - ContractId, - MerkleRoot, - MerkleStorage, - }, -}; -use itertools::Itertools; -use std::borrow::Cow; - -impl MerkleStorage for Database { - type Error = Error; - - fn insert( - &mut self, - parent: &ContractId, - key: &Bytes32, - value: &Bytes32, - ) -> Result, Error> { - let key = MultiKey::new((parent, key)); - Database::insert(self, key.as_ref().to_vec(), CONTRACTS_STATE, *value) - .map_err(Into::into) - } - - fn remove( - &mut self, - parent: &ContractId, - key: &Bytes32, - ) -> Result, Error> { - let key = MultiKey::new((parent, key)); - Database::remove(self, key.as_ref(), CONTRACTS_STATE).map_err(Into::into) - } - - fn get( - &self, - parent: &ContractId, - key: &Bytes32, - ) -> Result>, Error> { - let key = MultiKey::new((parent, key)); - self.get(key.as_ref(), CONTRACTS_STATE).map_err(Into::into) - } - - fn contains_key(&self, parent: &ContractId, key: &Bytes32) -> Result { - let key = MultiKey::new((parent, key)); - self.exists(key.as_ref(), CONTRACTS_STATE) - .map_err(Into::into) - } - - fn root(&mut self, parent: &ContractId) -> Result { - let items: Vec<_> = Database::iter_all::, Bytes32>( - self, - CONTRACTS_STATE, - 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(|| (key, value)) - }) - .sorted_by_key(|t| t.0) - .map(|(_, value)| value); - - Ok(crypto::ephemeral_merkle_root(root).into()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[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 database = Database::default(); - database - .insert(MultiKey::new(storage_id), CONTRACTS_STATE, stored_value) - .unwrap(); - - assert_eq!( - MerkleStorage::::get( - &database, - &storage_id.0, - &storage_id.1 - ) - .unwrap() - .unwrap() - .into_owned(), - 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 mut database = Database::default(); - MerkleStorage::::insert( - &mut database, - &storage_id.0, - &storage_id.1, - &stored_value, - ) - .unwrap(); - - let returned: Bytes32 = database - .get(MultiKey::new(storage_id).as_ref(), CONTRACTS_STATE) - .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 mut database = Database::default(); - database - .insert(MultiKey::new(storage_id), CONTRACTS_STATE, stored_value) - .unwrap(); - - MerkleStorage::::remove( - &mut database, - &storage_id.0, - &storage_id.1, - ) - .unwrap(); - - assert!(!database - .exists(MultiKey::new(storage_id).as_ref(), CONTRACTS_STATE) - .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 database = Database::default(); - database - .insert(MultiKey::new(storage_id), CONTRACTS_STATE, stored_value) - .unwrap(); - - assert!(MerkleStorage::::contains_key( - &database, - &storage_id.0, - &storage_id.1 - ) - .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 mut database = Database::default(); - - MerkleStorage::::insert( - &mut database, - &storage_id.0, - &storage_id.1, - &stored_value, - ) - .unwrap(); - - let root = MerkleStorage::::root( - &mut database, - &storage_id.0, - ); - assert!(root.is_ok()) - } -} diff --git a/fuel-core/src/database/storage.rs b/fuel-core/src/database/storage.rs new file mode 100644 index 00000000000..0422f95ec16 --- /dev/null +++ b/fuel-core/src/database/storage.rs @@ -0,0 +1,61 @@ +use fuel_core_interfaces::{ + common::{ + fuel_storage::Mappable, + fuel_tx::{ + Receipt, + UtxoId, + }, + }, + model::FuelBlockDb, +}; +use fuel_crypto::fuel_types::Bytes32; +use fuel_txpool::types::ContractId; + +pub mod balances; +pub mod block; +pub mod code_root; +pub mod coin; +pub mod contracts; +pub mod delegates_index; +pub mod message; +pub mod receipts; +pub mod staking_diffs; +pub mod state; +pub mod transaction; +pub mod validator_set; + +/// The table of blocks generated by Fuels validators. +/// Right now, we have only that type of block, but we will support others in the future. +pub struct FuelBlocks; + +impl Mappable for FuelBlocks { + /// Unique identifier of the fuel block. + type Key = Bytes32; + type SetValue = FuelBlockDb; + type GetValue = FuelBlockDb; +} + +/// The latest UTXO id of the contract. The contract's UTXO represents the unique id of the state. +/// After each transaction, old UTXO is consumed, and new UTXO is produced. UTXO is used as an +/// input to the next transaction related to the `ContractId` smart contract. +pub struct ContractsLatestUtxo; + +impl Mappable for ContractsLatestUtxo { + type Key = ContractId; + /// The latest UTXO id. + type SetValue = UtxoId; + type GetValue = UtxoId; +} + +/// Receipts of different hidden internal operations. +pub struct Receipts; + +impl Mappable for Receipts { + /// Unique identifier of the receipt. + type Key = Bytes32; + type SetValue = [Receipt]; + type GetValue = Vec; +} + +// TODO: Add macro to define all common tables to avoid copy/paste of the code. +// TODO: Add macro to define common unit tests. diff --git a/fuel-core/src/database/storage/balances.rs b/fuel-core/src/database/storage/balances.rs new file mode 100644 index 00000000000..48cef1134c7 --- /dev/null +++ b/fuel-core/src/database/storage/balances.rs @@ -0,0 +1,194 @@ +use crate::{ + database::{ + Column, + Database, + }, + state::{ + Error, + IterDirection, + MultiKey, + }, +}; +use fuel_core_interfaces::{ + common::{ + fuel_storage::{ + MerkleRoot, + StorageInspect, + StorageMutate, + }, + fuel_vm::{ + crypto, + prelude::{ + AssetId, + ContractId, + MerkleRootStorage, + Word, + }, + }, + }, + db::ContractsAssets, +}; +use itertools::Itertools; +use std::borrow::Cow; + +impl StorageInspect> for Database { + type Error = Error; + + fn get(&self, key: &(&ContractId, &AssetId)) -> Result>, Error> { + let key = MultiKey::new(key); + self.get(key.as_ref(), Column::Balances) + } + + fn contains_key(&self, key: &(&ContractId, &AssetId)) -> Result { + let key = MultiKey::new(key); + self.exists(key.as_ref(), Column::Balances) + } +} + +impl StorageMutate> for Database { + fn insert( + &mut self, + key: &(&ContractId, &AssetId), + value: &Word, + ) -> Result, Error> { + let key = MultiKey::new(key); + Database::insert(self, key.as_ref(), Column::Balances, *value) + } + + fn remove(&mut self, key: &(&ContractId, &AssetId)) -> Result, Error> { + let key = MultiKey::new(key); + Database::remove(self, key.as_ref(), Column::Balances) + } +} + +impl MerkleRootStorage> for Database { + fn root(&mut self, parent: &ContractId) -> Result { + let items: Vec<_> = Database::iter_all::, Word>( + self, + Column::Balances, + 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(|| (key, value)) + }) + .sorted_by_key(|t| t.0) + .map(|(_, value)| value.to_be_bytes()); + + 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 balance_id: (ContractId, AssetId) = + (ContractId::from([1u8; 32]), AssetId::new([1u8; 32])); + let balance: Word = 100; + let key = &(&balance_id.0, &balance_id.1); + + let database = &mut Database::default(); + database + .storage::() + .insert(key, &balance) + .unwrap(); + + assert_eq!( + database + .storage::() + .get(key) + .unwrap() + .unwrap() + .into_owned(), + balance + ); + } + + #[test] + fn put() { + let balance_id: (ContractId, AssetId) = + (ContractId::from([1u8; 32]), AssetId::new([1u8; 32])); + let balance: Word = 100; + let key = &(&balance_id.0, &balance_id.1); + + let database = &mut Database::default(); + database + .storage::() + .insert(key, &balance) + .unwrap(); + + let returned = database + .storage::() + .get(key) + .unwrap() + .unwrap(); + assert_eq!(*returned, balance); + } + + #[test] + fn remove() { + let balance_id: (ContractId, AssetId) = + (ContractId::from([1u8; 32]), AssetId::new([1u8; 32])); + let balance: Word = 100; + let key = &(&balance_id.0, &balance_id.1); + + let database = &mut Database::default(); + database + .storage::() + .insert(key, &balance) + .unwrap(); + + database.storage::().remove(key).unwrap(); + + assert!(!database + .storage::() + .contains_key(key) + .unwrap()); + } + + #[test] + fn exists() { + let balance_id: (ContractId, AssetId) = + (ContractId::from([1u8; 32]), AssetId::new([1u8; 32])); + let balance: Word = 100; + let key = &(&balance_id.0, &balance_id.1); + + let database = &mut Database::default(); + database + .storage::() + .insert(key, &balance) + .unwrap(); + + assert!(database + .storage::() + .contains_key(key) + .unwrap()); + } + + #[test] + fn root() { + let balance_id: (ContractId, AssetId) = + (ContractId::from([1u8; 32]), AssetId::new([1u8; 32])); + let balance: Word = 100; + let key = &(&balance_id.0, &balance_id.1); + + let database = &mut Database::default(); + + database + .storage::() + .insert(key, &balance) + .unwrap(); + + let root = database.storage::().root(&balance_id.0); + assert!(root.is_ok()) + } +} diff --git a/fuel-core/src/database/block.rs b/fuel-core/src/database/storage/block.rs similarity index 65% rename from fuel-core/src/database/block.rs rename to fuel-core/src/database/storage/block.rs index d133f0713cf..a84be10f7a8 100644 --- a/fuel-core/src/database/block.rs +++ b/fuel-core/src/database/storage/block.rs @@ -1,9 +1,7 @@ use crate::{ database::{ - columns::{ - BLOCKS, - BLOCK_IDS, - }, + storage::FuelBlocks, + Column, Database, KvStoreError, }, @@ -17,7 +15,10 @@ use crate::{ }, }; use fuel_core_interfaces::common::{ - fuel_storage::Storage, + fuel_storage::{ + StorageInspect, + StorageMutate, + }, fuel_tx::Bytes32, }; use std::{ @@ -28,40 +29,51 @@ use std::{ }, }; -impl Storage for Database { +impl StorageInspect for Database { type Error = KvStoreError; + fn get(&self, key: &Bytes32) -> Result>, KvStoreError> { + Database::get(self, key.as_ref(), Column::Blocks).map_err(Into::into) + } + + fn contains_key(&self, key: &Bytes32) -> Result { + Database::exists(self, key.as_ref(), Column::Blocks).map_err(Into::into) + } +} + +impl StorageMutate for Database { fn insert( &mut self, key: &Bytes32, value: &FuelBlockDb, ) -> Result, KvStoreError> { - Database::insert(self, value.headers.height, BLOCK_IDS, *key)?; - Database::insert(self, key.as_ref(), BLOCKS, value.clone()).map_err(Into::into) + let _: Option = Database::insert( + self, + value.headers.height.to_be_bytes(), + Column::BlockIds, + *key, + )?; + Database::insert(self, key.as_ref(), Column::Blocks, value).map_err(Into::into) } fn remove(&mut self, key: &Bytes32) -> Result, KvStoreError> { - let block: Option = Database::remove(self, key.as_ref(), BLOCKS)?; + let block: Option = + Database::remove(self, key.as_ref(), Column::Blocks)?; if let Some(block) = &block { - let _: Option = - Database::remove(self, &block.headers.height.to_bytes(), BLOCK_IDS)?; + let _: Option = Database::remove( + self, + &block.headers.height.to_be_bytes(), + Column::BlockIds, + )?; } Ok(block) } - - fn get(&self, key: &Bytes32) -> Result>, KvStoreError> { - Database::get(self, key.as_ref(), BLOCKS).map_err(Into::into) - } - - fn contains_key(&self, key: &Bytes32) -> Result { - Database::exists(self, key.as_ref(), BLOCKS).map_err(Into::into) - } } impl Database { pub fn get_block_height(&self) -> Result, Error> { let block_entry: Option<(Vec, Bytes32)> = self - .iter_all(BLOCK_IDS, None, None, Some(IterDirection::Reverse)) + .iter_all(Column::BlockIds, None, None, Some(IterDirection::Reverse)) .next() .transpose()?; // get block height from most recently indexed block @@ -78,7 +90,7 @@ impl Database { } pub fn get_block_id(&self, height: BlockHeight) -> Result, Error> { - Database::get(self, &height.to_bytes()[..], BLOCK_IDS) + Database::get(self, &height.to_bytes()[..], Column::BlockIds) } pub fn all_block_ids( @@ -87,7 +99,7 @@ impl Database { direction: Option, ) -> impl Iterator> + '_ { let start = start.map(|b| b.to_bytes().to_vec()); - self.iter_all::, Bytes32>(BLOCK_IDS, None, start, direction) + self.iter_all::, Bytes32>(Column::BlockIds, None, start, direction) .map(|res| { let (height, id) = res?; Ok(( diff --git a/fuel-core/src/database/code_root.rs b/fuel-core/src/database/storage/code_root.rs similarity index 54% rename from fuel-core/src/database/code_root.rs rename to fuel-core/src/database/storage/code_root.rs index 03c6e9ad5ce..9eb7bac0dbf 100644 --- a/fuel-core/src/database/code_root.rs +++ b/fuel-core/src/database/storage/code_root.rs @@ -1,46 +1,59 @@ use crate::{ database::{ - columns::CONTRACTS_CODE_ROOT, + Column, Database, }, state::Error, }; -use fuel_core_interfaces::common::fuel_vm::prelude::{ - Bytes32, - ContractId, - Salt, - Storage, +use fuel_core_interfaces::{ + common::{ + fuel_storage::{ + StorageInspect, + StorageMutate, + }, + fuel_vm::prelude::{ + Bytes32, + ContractId, + Salt, + }, + }, + db::ContractsInfo, }; use std::borrow::Cow; -impl Storage for Database { +impl StorageInspect for Database { type Error = Error; + fn get(&self, key: &ContractId) -> Result>, Error> { + Database::get(self, key.as_ref(), Column::ContractsInfo) + } + + fn contains_key(&self, key: &ContractId) -> Result { + Database::exists(self, key.as_ref(), Column::ContractsInfo) + } +} + +impl StorageMutate for Database { fn insert( &mut self, key: &ContractId, value: &(Salt, Bytes32), ) -> Result, Error> { - Database::insert(self, key.as_ref(), CONTRACTS_CODE_ROOT, *value) + Database::insert(self, key.as_ref(), Column::ContractsInfo, *value) } fn remove(&mut self, key: &ContractId) -> Result, Error> { - Database::remove(self, key.as_ref(), CONTRACTS_CODE_ROOT) - } - - fn get(&self, key: &ContractId) -> Result>, Error> { - Database::get(self, key.as_ref(), CONTRACTS_CODE_ROOT) - } - - fn contains_key(&self, key: &ContractId) -> Result { - Database::exists(self, key.as_ref(), CONTRACTS_CODE_ROOT) + Database::remove(self, key.as_ref(), Column::ContractsInfo) } } #[cfg(test)] mod tests { use super::*; - use fuel_core_interfaces::common::fuel_vm::prelude::Contract; + use fuel_core_interfaces::common::{ + fuel_storage::StorageAsMut, + fuel_vm::prelude::Contract, + }; use rand::{ rngs::StdRng, Rng, @@ -55,17 +68,16 @@ mod tests { let root = contract.root(); let salt: Salt = rng.gen(); - let database = Database::default(); + let database = &mut Database::default(); database - .insert( - contract_id.as_ref().to_vec(), - CONTRACTS_CODE_ROOT, - (salt, root), - ) + .storage::() + .insert(&contract_id, &(salt, root)) .unwrap(); assert_eq!( - Storage::::get(&database, &contract_id) + database + .storage::() + .get(&contract_id) .unwrap() .unwrap() .into_owned(), @@ -81,16 +93,15 @@ mod tests { let root = contract.root(); let salt: Salt = rng.gen(); - let mut database = Database::default(); - Storage::::insert( - &mut database, - &contract_id, - &(salt, root), - ) - .unwrap(); + let database = &mut Database::default(); + database + .storage::() + .insert(&contract_id, &(salt, root)) + .unwrap(); - let returned: (Salt, Bytes32) = database - .get(contract_id.as_ref(), CONTRACTS_CODE_ROOT) + let returned: (Salt, Bytes32) = *database + .storage::() + .get(&contract_id) .unwrap() .unwrap(); assert_eq!(returned, (salt, root)); @@ -104,20 +115,19 @@ mod tests { let root = contract.root(); let salt: Salt = rng.gen(); - let mut database = Database::default(); + let database = &mut Database::default(); database - .insert( - contract_id.as_ref().to_vec(), - CONTRACTS_CODE_ROOT, - (salt, root), - ) + .storage::() + .insert(&contract_id, &(salt, root)) .unwrap(); - Storage::::remove(&mut database, &contract_id) + database + .storage::() + .remove(&contract_id) .unwrap(); assert!(!database - .exists(contract_id.as_ref(), CONTRACTS_CODE_ROOT) + .exists(contract_id.as_ref(), Column::ContractsInfo) .unwrap()); } @@ -129,19 +139,15 @@ mod tests { let root = contract.root(); let salt: Salt = rng.gen(); - let database = Database::default(); + let database = &mut Database::default(); database - .insert( - contract_id.as_ref().to_vec(), - CONTRACTS_CODE_ROOT, - (salt, root), - ) + .storage::() + .insert(&contract_id, &(salt, root)) .unwrap(); - assert!(Storage::::contains_key( - &database, - &contract_id - ) - .unwrap()); + assert!(database + .storage::() + .contains_key(&contract_id) + .unwrap()); } } diff --git a/fuel-core/src/database/coin.rs b/fuel-core/src/database/storage/coin.rs similarity index 79% rename from fuel-core/src/database/coin.rs rename to fuel-core/src/database/storage/coin.rs index e16e6f02789..fddce439306 100644 --- a/fuel-core/src/database/coin.rs +++ b/fuel-core/src/database/storage/coin.rs @@ -1,11 +1,7 @@ use crate::{ chain_config::CoinConfig, database::{ - columns::{ - self, - COIN, - OWNED_COINS, - }, + Column, Database, KvStoreError, }, @@ -17,7 +13,11 @@ use crate::{ }; use fuel_core_interfaces::{ common::{ - fuel_storage::Storage, + fuel_storage::{ + StorageAsRef, + StorageInspect, + StorageMutate, + }, fuel_tx::{ Address, AssetId, @@ -25,7 +25,7 @@ use fuel_core_interfaces::{ UtxoId, }, }, - model::Coin as CoinModel, + db::Coins, }; use itertools::Itertools; use std::borrow::Cow; @@ -49,9 +49,19 @@ fn utxo_id_to_bytes(utxo_id: &UtxoId) -> Vec { out } -impl Storage for Database { +impl StorageInspect for Database { type Error = KvStoreError; + fn get(&self, key: &UtxoId) -> Result>, KvStoreError> { + Database::get(self, &utxo_id_to_bytes(key), Column::Coins).map_err(Into::into) + } + + fn contains_key(&self, key: &UtxoId) -> Result { + Database::exists(self, &utxo_id_to_bytes(key), Column::Coins).map_err(Into::into) + } +} + +impl StorageMutate for Database { fn insert( &mut self, key: &UtxoId, @@ -59,34 +69,26 @@ impl Storage for Database { ) -> Result, KvStoreError> { let coin_by_owner: Vec = owner_coin_id_key(&value.owner, key); // insert primary record - let insert = - Database::insert(self, utxo_id_to_bytes(key), columns::COIN, value.clone())?; + let insert = Database::insert(self, utxo_id_to_bytes(key), Column::Coins, value)?; // insert secondary index by owner - Database::insert(self, coin_by_owner, columns::OWNED_COINS, true)?; + let _: Option = + Database::insert(self, coin_by_owner, Column::OwnedCoins, true)?; Ok(insert) } fn remove(&mut self, key: &UtxoId) -> Result, KvStoreError> { let coin: Option = - Database::remove(self, &utxo_id_to_bytes(key), columns::COIN)?; + Database::remove(self, &utxo_id_to_bytes(key), Column::Coins)?; // cleanup secondary index if let Some(coin) = &coin { let key = owner_coin_id_key(&coin.owner, key); let _: Option = - Database::remove(self, key.as_slice(), columns::OWNED_COINS)?; + Database::remove(self, key.as_slice(), Column::OwnedCoins)?; } Ok(coin) } - - fn get(&self, key: &UtxoId) -> Result>, KvStoreError> { - Database::get(self, &utxo_id_to_bytes(key), columns::COIN).map_err(Into::into) - } - - fn contains_key(&self, key: &UtxoId) -> Result { - Database::exists(self, &utxo_id_to_bytes(key), columns::COIN).map_err(Into::into) - } } impl Database { @@ -97,7 +99,7 @@ impl Database { direction: Option, ) -> impl Iterator> + '_ { self.iter_all::, bool>( - OWNED_COINS, + Column::OwnedCoins, Some(owner.as_ref().to_vec()), start_coin.map(|b| owner_coin_id_key(&owner, &b)), direction, @@ -122,7 +124,7 @@ impl Database { direction: Option, ) -> impl Iterator> + '_ { self.iter_all::, bool>( - OWNED_COINS, + Column::OwnedCoins, Some(owner.as_ref().to_vec()), start_coin.map(|b| owner_coin_id_key(&owner, &b)), direction, @@ -136,18 +138,12 @@ impl Database { ) }) }) - .filter_ok(move |id| { - Storage::::get(self, id) - .unwrap() - .unwrap() - .asset_id - == asset_id - }) + .filter_ok(move |id| self.storage::().get(id).unwrap().unwrap().asset_id == asset_id) } pub fn get_coin_config(&self) -> anyhow::Result>> { let configs = self - .iter_all::, CoinModel>(COIN, None, None, None) + .iter_all::, Coin>(Column::Coins, None, None, None) .map(|raw_coin| -> Result { let coin = raw_coin?; diff --git a/fuel-core/src/database/contracts.rs b/fuel-core/src/database/storage/contracts.rs similarity index 59% rename from fuel-core/src/database/contracts.rs rename to fuel-core/src/database/storage/contracts.rs index b17ad234ff4..77b11a73a59 100644 --- a/fuel-core/src/database/contracts.rs +++ b/fuel-core/src/database/storage/contracts.rs @@ -1,12 +1,8 @@ use crate::{ chain_config::ContractConfig, database::{ - columns::{ - BALANCES, - CONTRACTS, - CONTRACTS_STATE, - CONTRACT_UTXO_ID, - }, + storage::ContractsLatestUtxo, + Column, Database, InterpreterStorage, }, @@ -16,69 +12,77 @@ use crate::{ MultiKey, }, }; -use fuel_core_interfaces::common::{ - fuel_tx::UtxoId, - fuel_types::{ - Bytes32, - Word, - }, - fuel_vm::prelude::{ - AssetId, - Contract, - ContractId, - Storage, +use fuel_core_interfaces::{ + common::{ + fuel_storage::{ + StorageAsRef, + StorageInspect, + StorageMutate, + }, + fuel_tx::UtxoId, + fuel_types::{ + Bytes32, + Word, + }, + fuel_vm::prelude::{ + AssetId, + Contract, + ContractId, + }, }, + db::ContractsRawCode, }; use std::borrow::Cow; -impl Storage for Database { +impl StorageInspect for Database { type Error = Error; + fn get(&self, key: &ContractId) -> Result>, Error> { + self.get(key.as_ref(), Column::ContractsRawCode) + } + + fn contains_key(&self, key: &ContractId) -> Result { + self.exists(key.as_ref(), Column::ContractsRawCode) + } +} + +impl StorageMutate for Database { fn insert( &mut self, key: &ContractId, - value: &Contract, + value: &[u8], ) -> Result, Error> { - Database::insert(self, key.as_ref(), CONTRACTS, value.clone()) + Database::insert(self, key.as_ref(), Column::ContractsRawCode, value) } fn remove(&mut self, key: &ContractId) -> Result, Error> { - Database::remove(self, key.as_ref(), CONTRACTS) + Database::remove(self, key.as_ref(), Column::ContractsRawCode) } +} - fn get(&self, key: &ContractId) -> Result>, Error> { - self.get(key.as_ref(), CONTRACTS) +impl StorageInspect for Database { + type Error = Error; + + fn get(&self, key: &ContractId) -> Result>, Self::Error> { + self.get(key.as_ref(), Column::ContractUtxoId) } - fn contains_key(&self, key: &ContractId) -> Result { - self.exists(key.as_ref(), CONTRACTS) + fn contains_key(&self, key: &ContractId) -> Result { + self.exists(key.as_ref(), Column::ContractUtxoId) } } -impl Storage for Database { - type Error = Error; - +impl StorageMutate for Database { fn insert( &mut self, key: &ContractId, value: &UtxoId, ) -> Result, Self::Error> { - Database::insert(self, key.as_ref(), CONTRACT_UTXO_ID, *value) + Database::insert(self, key.as_ref(), Column::ContractUtxoId, *value) } fn remove(&mut self, key: &ContractId) -> Result, Self::Error> { - Database::remove(self, key.as_ref(), CONTRACT_UTXO_ID) - } - - fn get<'a>( - &'a self, - key: &ContractId, - ) -> Result>, Self::Error> { - self.get(key.as_ref(), CONTRACT_UTXO_ID) - } - - fn contains_key(&self, key: &ContractId) -> Result { - self.exists(key.as_ref(), CONTRACT_UTXO_ID) + Database::remove(self, key.as_ref(), Column::ContractUtxoId) } } @@ -90,10 +94,10 @@ impl Database { direction: Option, ) -> impl Iterator> + '_ { self.iter_all::, Word>( - BALANCES, + Column::Balances, Some(contract.as_ref().to_vec()), start_asset - .map(|asset_id| MultiKey::new((&contract, &asset_id)).as_ref().to_vec()), + .map(|asset_id| MultiKey::new(&(&contract, &asset_id)).as_ref().to_vec()), direction, ) .map(|res| { @@ -107,16 +111,17 @@ impl Database { &self, ) -> Result>, anyhow::Error> { let configs = self - .iter_all::, Word>(CONTRACTS, None, None, None) + .iter_all::, Word>(Column::ContractsRawCode, None, None, None) .map(|raw_contract_id| -> Result { let contract_id = ContractId::new(raw_contract_id.unwrap().0[..32].try_into()?); - let code: Vec = - Storage::::get(self, &contract_id)? - .unwrap() - .into_owned() - .into(); + let code: Vec = self + .storage::() + .get(&contract_id)? + .unwrap() + .into_owned() + .into(); let salt = InterpreterStorage::storage_contract_root(self, &contract_id)? .unwrap() @@ -125,7 +130,7 @@ impl Database { let state = Some( self.iter_all::, Bytes32>( - CONTRACTS_STATE, + Column::ContractsState, Some(contract_id.as_ref().to_vec()), None, None, @@ -145,7 +150,7 @@ impl Database { let balances = Some( self.iter_all::, u64>( - BALANCES, + Column::Balances, Some(contract_id.as_ref().to_vec()), None, None, @@ -177,21 +182,27 @@ impl Database { #[cfg(test)] mod tests { use super::*; - use fuel_core_interfaces::common::fuel_tx::TxId; + use fuel_core_interfaces::common::{ + fuel_storage::StorageAsMut, + fuel_tx::TxId, + }; #[test] fn contract_get() { let contract_id: ContractId = ContractId::from([1u8; 32]); let contract: Contract = Contract::from(vec![32u8]); - let database = Database::default(); + let database = &mut Database::default(); database - .insert(contract_id.as_ref().to_vec(), CONTRACTS, contract.clone()) + .storage::() + .insert(&contract_id, contract.as_ref()) .unwrap(); assert_eq!( - Storage::::get(&database, &contract_id) + database + .storage::() + .get(&contract_id) .unwrap() .unwrap() .into_owned(), @@ -204,14 +215,18 @@ mod tests { let contract_id: ContractId = ContractId::from([1u8; 32]); let contract: Contract = Contract::from(vec![32u8]); - let mut database = Database::default(); - Storage::::insert(&mut database, &contract_id, &contract) + let database = &mut Database::default(); + database + .storage::() + .insert(&contract_id, contract.as_ref()) .unwrap(); let returned: Contract = database - .get(contract_id.as_ref(), CONTRACTS) + .storage::() + .get(&contract_id) .unwrap() - .unwrap(); + .unwrap() + .into_owned(); assert_eq!(returned, contract); } @@ -220,14 +235,21 @@ mod tests { let contract_id: ContractId = ContractId::from([1u8; 32]); let contract: Contract = Contract::from(vec![32u8]); - let mut database = Database::default(); + let database = &mut Database::default(); database - .insert(contract_id.as_ref().to_vec(), CONTRACTS, contract) + .storage::() + .insert(&contract_id, contract.as_ref()) .unwrap(); - Storage::::remove(&mut database, &contract_id).unwrap(); + database + .storage::() + .remove(&contract_id) + .unwrap(); - assert!(!database.exists(contract_id.as_ref(), CONTRACTS).unwrap()); + assert!(!database + .storage::() + .contains_key(&contract_id) + .unwrap()); } #[test] @@ -235,15 +257,16 @@ mod tests { let contract_id: ContractId = ContractId::from([1u8; 32]); let contract: Contract = Contract::from(vec![32u8]); - let database = Database::default(); + let database = &mut Database::default(); database - .insert(contract_id.as_ref().to_vec(), CONTRACTS, contract) + .storage::() + .insert(&contract_id, contract.as_ref()) .unwrap(); - assert!( - Storage::::contains_key(&database, &contract_id) - .unwrap() - ); + assert!(database + .storage::() + .contains_key(&contract_id) + .unwrap()); } #[test] @@ -251,14 +274,17 @@ mod tests { let contract_id: ContractId = ContractId::from([1u8; 32]); let utxo_id: UtxoId = UtxoId::new(TxId::new([2u8; 32]), 4); - let database = Database::default(); + let database = &mut Database::default(); database - .insert(contract_id.as_ref().to_vec(), CONTRACT_UTXO_ID, utxo_id) + .storage::() + .insert(&contract_id, &utxo_id) .unwrap(); assert_eq!( - Storage::::get(&database, &contract_id) + database + .storage::() + .get(&contract_id) .unwrap() .unwrap() .into_owned(), @@ -271,12 +297,15 @@ mod tests { let contract_id: ContractId = ContractId::from([1u8; 32]); let utxo_id: UtxoId = UtxoId::new(TxId::new([2u8; 32]), 4); - let mut database = Database::default(); - Storage::::insert(&mut database, &contract_id, &utxo_id) + let database = &mut Database::default(); + database + .storage::() + .insert(&contract_id, &utxo_id) .unwrap(); - let returned: UtxoId = database - .get(contract_id.as_ref(), CONTRACT_UTXO_ID) + let returned: UtxoId = *database + .storage::() + .get(&contract_id) .unwrap() .unwrap(); assert_eq!(returned, utxo_id); @@ -287,15 +316,20 @@ mod tests { let contract_id: ContractId = ContractId::from([1u8; 32]); let utxo_id: UtxoId = UtxoId::new(TxId::new([2u8; 32]), 4); - let mut database = Database::default(); + let database = &mut Database::default(); database - .insert(contract_id.as_ref().to_vec(), CONTRACT_UTXO_ID, utxo_id) + .storage::() + .insert(&contract_id, &utxo_id) .unwrap(); - Storage::::remove(&mut database, &contract_id).unwrap(); + database + .storage::() + .remove(&contract_id) + .unwrap(); assert!(!database - .exists(contract_id.as_ref(), CONTRACT_UTXO_ID) + .storage::() + .contains_key(&contract_id) .unwrap()); } @@ -304,13 +338,15 @@ mod tests { let contract_id: ContractId = ContractId::from([1u8; 32]); let utxo_id: UtxoId = UtxoId::new(TxId::new([2u8; 32]), 4); - let database = Database::default(); + let database = &mut Database::default(); database - .insert(contract_id.as_ref().to_vec(), CONTRACT_UTXO_ID, utxo_id) + .storage::() + .insert(&contract_id, &utxo_id) .unwrap(); - assert!( - Storage::::contains_key(&database, &contract_id).unwrap() - ); + assert!(database + .storage::() + .contains_key(&contract_id) + .unwrap()); } } diff --git a/fuel-core/src/database/delegates_index.rs b/fuel-core/src/database/storage/delegates_index.rs similarity index 55% rename from fuel-core/src/database/delegates_index.rs rename to fuel-core/src/database/storage/delegates_index.rs index 3d8acfdaa12..fc1431c69b3 100644 --- a/fuel-core/src/database/delegates_index.rs +++ b/fuel-core/src/database/storage/delegates_index.rs @@ -1,28 +1,43 @@ use crate::database::{ - columns, + Column, Database, KvStoreError, }; use fuel_core_interfaces::{ common::{ - fuel_storage::Storage, + fuel_storage::{ + StorageInspect, + StorageMutate, + }, fuel_types::Address, }, + db::DelegatesIndexes, model::DaBlockHeight, }; use std::borrow::Cow; -/// Delegate Index maps delegateAddress with list of da block where delegation happened. so that we -/// can access those changes -impl Storage> for Database { +impl StorageInspect for Database { type Error = KvStoreError; + fn get( + &self, + key: &Address, + ) -> Result>>, KvStoreError> { + Database::get(self, key.as_ref(), Column::DelegatesIndex).map_err(Into::into) + } + + fn contains_key(&self, key: &Address) -> Result { + Database::exists(self, key.as_ref(), Column::DelegatesIndex).map_err(Into::into) + } +} + +impl StorageMutate for Database { fn insert( &mut self, key: &Address, - value: &Vec, + value: &[DaBlockHeight], ) -> Result>, KvStoreError> { - Database::insert(self, key.as_ref(), columns::VALIDATOR_SET, value.clone()) + Database::insert(self, key.as_ref(), Column::DelegatesIndex, value) .map_err(Into::into) } @@ -30,17 +45,6 @@ impl Storage> for Database { &mut self, key: &Address, ) -> Result>, KvStoreError> { - Database::remove(self, key.as_ref(), columns::VALIDATOR_SET).map_err(Into::into) - } - - fn get( - &self, - key: &Address, - ) -> Result>>, KvStoreError> { - Database::get(self, key.as_ref(), columns::VALIDATOR_SET).map_err(Into::into) - } - - fn contains_key(&self, key: &Address) -> Result { - Database::exists(self, key.as_ref(), columns::VALIDATOR_SET).map_err(Into::into) + Database::remove(self, key.as_ref(), Column::DelegatesIndex).map_err(Into::into) } } diff --git a/fuel-core/src/database/message.rs b/fuel-core/src/database/storage/message.rs similarity index 77% rename from fuel-core/src/database/message.rs rename to fuel-core/src/database/storage/message.rs index 7af93b0699d..ff8b162efb0 100644 --- a/fuel-core/src/database/message.rs +++ b/fuel-core/src/database/storage/message.rs @@ -1,7 +1,7 @@ use crate::{ chain_config::MessageConfig, database::{ - columns, + Column, Database, KvStoreError, }, @@ -12,13 +12,17 @@ use crate::{ }; use fuel_core_interfaces::{ common::{ - fuel_storage::Storage, + fuel_storage::{ + StorageInspect, + StorageMutate, + }, fuel_types::{ Address, Bytes32, MessageId, }, }, + db::Messages, model::Message, }; use std::{ @@ -26,9 +30,19 @@ use std::{ ops::Deref, }; -impl Storage for Database { +impl StorageInspect for Database { type Error = KvStoreError; + fn get(&self, key: &MessageId) -> Result>, KvStoreError> { + Database::get(self, key.as_ref(), Column::Messages).map_err(Into::into) + } + + fn contains_key(&self, key: &MessageId) -> Result { + Database::exists(self, key.as_ref(), Column::Messages).map_err(Into::into) + } +} + +impl StorageMutate for Database { fn insert( &mut self, key: &MessageId, @@ -36,13 +50,13 @@ impl Storage for Database { ) -> Result, KvStoreError> { // insert primary record let result = - Database::insert(self, key.as_ref(), columns::MESSAGES, value.clone())?; + Database::insert(self, key.as_ref(), Column::Messages, value.clone())?; // insert secondary record by owner - Database::insert( + let _: Option = Database::insert( self, owner_msg_id_key(&value.owner, key), - columns::OWNED_MESSAGE_IDS, + Column::OwnedMessageIds, true, )?; @@ -51,26 +65,18 @@ impl Storage for Database { fn remove(&mut self, key: &MessageId) -> Result, KvStoreError> { let result: Option = - Database::remove(self, key.as_ref(), columns::MESSAGES)?; + Database::remove(self, key.as_ref(), Column::Messages)?; if let Some(message) = &result { Database::remove::( self, &owner_msg_id_key(&message.owner, key), - columns::OWNED_MESSAGE_IDS, + Column::OwnedMessageIds, )?; } Ok(result) } - - fn get(&self, key: &MessageId) -> Result>, KvStoreError> { - Database::get(self, key.as_ref(), columns::MESSAGES).map_err(Into::into) - } - - fn contains_key(&self, key: &MessageId) -> Result { - Database::exists(self, key.as_ref(), columns::MESSAGES).map_err(Into::into) - } } impl Database { @@ -81,7 +87,7 @@ impl Database { direction: Option, ) -> impl Iterator> + '_ { self.iter_all::, bool>( - columns::OWNED_MESSAGE_IDS, + Column::OwnedMessageIds, Some(owner.as_ref().to_vec()), start_message_id.map(|msg_id| owner_msg_id_key(&owner, &msg_id)), direction, @@ -100,7 +106,7 @@ impl Database { direction: Option, ) -> impl Iterator> + '_ { let start = start.map(|v| v.deref().to_vec()); - self.iter_all::, Message>(columns::MESSAGES, None, start, direction) + self.iter_all::, Message>(Column::Messages, None, start, direction) .map(|res| res.map(|(_, message)| message)) } @@ -139,6 +145,7 @@ fn owner_msg_id_key(owner: &Address, msg_id: &MessageId) -> Vec { #[cfg(test)] mod tests { use super::*; + use fuel_core_interfaces::common::fuel_storage::StorageAsMut; #[test] fn owned_message_ids() { @@ -147,20 +154,24 @@ mod tests { // insert a message with the first id let first_id = MessageId::new([1; 32]); - let _ = - Storage::::insert(&mut db, &first_id, &message).unwrap(); + let _ = db + .storage::() + .insert(&first_id, &message) + .unwrap(); // insert a message with the second id with the same Owner let second_id = MessageId::new([2; 32]); - let _ = - Storage::::insert(&mut db, &second_id, &message).unwrap(); + let _ = db + .storage::() + .insert(&second_id, &message) + .unwrap(); // verify that 2 message IDs are associated with a single Owner let owned_msg_ids = db.owned_message_ids(message.owner, None, None); assert_eq!(owned_msg_ids.count(), 2); // remove the first message with its given id - let _ = Storage::::remove(&mut db, &first_id).unwrap(); + let _ = db.storage::().remove(&first_id).unwrap(); // verify that only second ID is left let owned_msg_ids: Vec<_> = @@ -169,7 +180,7 @@ mod tests { assert_eq!(owned_msg_ids.len(), 1); // remove the second message with its given id - let _ = Storage::::remove(&mut db, &second_id).unwrap(); + let _ = db.storage::().remove(&second_id).unwrap(); let owned_msg_ids = db.owned_message_ids(message.owner, None, None); assert_eq!(owned_msg_ids.count(), 0); } diff --git a/fuel-core/src/database/receipts.rs b/fuel-core/src/database/storage/receipts.rs similarity index 51% rename from fuel-core/src/database/receipts.rs rename to fuel-core/src/database/storage/receipts.rs index 876032457ce..1a03e037ea6 100644 --- a/fuel-core/src/database/receipts.rs +++ b/fuel-core/src/database/storage/receipts.rs @@ -1,10 +1,14 @@ use crate::database::{ - columns::RECEIPTS, + storage::Receipts, + Column, Database, KvStoreError, }; use fuel_core_interfaces::common::{ - fuel_storage::Storage, + fuel_storage::{ + StorageInspect, + StorageMutate, + }, fuel_tx::{ Bytes32, Receipt, @@ -12,26 +16,28 @@ use fuel_core_interfaces::common::{ }; use std::borrow::Cow; -impl Storage> for Database { +impl StorageInspect for Database { type Error = KvStoreError; + fn get(&self, key: &Bytes32) -> Result>>, KvStoreError> { + Database::get(self, key.as_ref(), Column::Receipts).map_err(Into::into) + } + + fn contains_key(&self, key: &Bytes32) -> Result { + Database::exists(self, key.as_ref(), Column::Receipts).map_err(Into::into) + } +} + +impl StorageMutate for Database { fn insert( &mut self, key: &Bytes32, - value: &Vec, + value: &[Receipt], ) -> Result>, KvStoreError> { - Database::insert(self, key.as_ref(), RECEIPTS, value.clone()).map_err(Into::into) + Database::insert(self, key.as_ref(), Column::Receipts, value).map_err(Into::into) } fn remove(&mut self, key: &Bytes32) -> Result>, KvStoreError> { - Database::remove(self, key.as_ref(), RECEIPTS).map_err(Into::into) - } - - fn get(&self, key: &Bytes32) -> Result>>, KvStoreError> { - Database::get(self, key.as_ref(), RECEIPTS).map_err(Into::into) - } - - fn contains_key(&self, key: &Bytes32) -> Result { - Database::exists(self, key.as_ref(), RECEIPTS).map_err(Into::into) + Database::remove(self, key.as_ref(), Column::Receipts).map_err(Into::into) } } diff --git a/fuel-core/src/database/staking_diffs.rs b/fuel-core/src/database/storage/staking_diffs.rs similarity index 63% rename from fuel-core/src/database/staking_diffs.rs rename to fuel-core/src/database/storage/staking_diffs.rs index 64a5290c5eb..6c1c823069b 100644 --- a/fuel-core/src/database/staking_diffs.rs +++ b/fuel-core/src/database/storage/staking_diffs.rs @@ -1,18 +1,33 @@ use crate::database::{ - columns, + Column, Database, KvStoreError, }; use fuel_core_interfaces::{ - common::fuel_storage::Storage, + common::fuel_storage::{ + StorageInspect, + StorageMutate, + }, + db::StackingDiffs, model::DaBlockHeight, relayer::StakingDiff, }; use std::borrow::Cow; -impl Storage for Database { +impl StorageInspect for Database { type Error = KvStoreError; + fn get(&self, key: &DaBlockHeight) -> Result>, KvStoreError> { + Database::get(self, &key.to_be_bytes(), Column::StackingDiffs).map_err(Into::into) + } + + fn contains_key(&self, key: &DaBlockHeight) -> Result { + Database::exists(self, &key.to_be_bytes(), Column::StackingDiffs) + .map_err(Into::into) + } +} + +impl StorageMutate for Database { fn insert( &mut self, key: &DaBlockHeight, @@ -21,7 +36,7 @@ impl Storage for Database { Database::insert( self, key.to_be_bytes(), - columns::STAKING_DIFFS, + Column::StackingDiffs, value.clone(), ) .map_err(Into::into) @@ -31,17 +46,7 @@ impl Storage for Database { &mut self, key: &DaBlockHeight, ) -> Result, KvStoreError> { - Database::remove(self, &key.to_be_bytes(), columns::STAKING_DIFFS) - .map_err(Into::into) - } - - fn get(&self, key: &DaBlockHeight) -> Result>, KvStoreError> { - Database::get(self, &key.to_be_bytes(), columns::STAKING_DIFFS) - .map_err(Into::into) - } - - fn contains_key(&self, key: &DaBlockHeight) -> Result { - Database::exists(self, &key.to_be_bytes(), columns::STAKING_DIFFS) + Database::remove(self, &key.to_be_bytes(), Column::StackingDiffs) .map_err(Into::into) } } diff --git a/fuel-core/src/database/storage/state.rs b/fuel-core/src/database/storage/state.rs new file mode 100644 index 00000000000..47136cd82c4 --- /dev/null +++ b/fuel-core/src/database/storage/state.rs @@ -0,0 +1,198 @@ +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> for Database { + type Error = Error; + + fn get(&self, key: &(&ContractId, &Bytes32)) -> Result>, 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 { + let key = MultiKey::new(key); + self.exists(key.as_ref(), Column::ContractsState) + .map_err(Into::into) + } +} + +impl StorageMutate> for Database { + fn insert( + &mut self, + key: &(&ContractId, &Bytes32), + value: &Bytes32, + ) -> Result, 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, Error> { + let key = MultiKey::new(key); + Database::remove(self, key.as_ref(), Column::ContractsState).map_err(Into::into) + } +} + +impl MerkleRootStorage> for Database { + fn root(&mut self, parent: &ContractId) -> Result { + let items: Vec<_> = Database::iter_all::, 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(|| (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::() + .insert(key, &stored_value) + .unwrap(); + + assert_eq!( + *database + .storage::() + .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::() + .insert(key, &stored_value) + .unwrap(); + + let returned: Bytes32 = *database + .storage::() + .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::() + .insert(key, &stored_value) + .unwrap(); + + database.storage::().remove(key).unwrap(); + + assert!(!database + .storage::() + .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::() + .insert(key, &stored_value) + .unwrap(); + + assert!(database + .storage::() + .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::() + .insert(key, &stored_value) + .unwrap(); + + let root = database.storage::().root(&storage_id.0); + assert!(root.is_ok()) + } +} diff --git a/fuel-core/src/database/storage/transaction.rs b/fuel-core/src/database/storage/transaction.rs new file mode 100644 index 00000000000..c3dda2588e9 --- /dev/null +++ b/fuel-core/src/database/storage/transaction.rs @@ -0,0 +1,140 @@ +use crate::{ + database::{ + transaction::{ + OwnedTransactionIndexCursor, + OwnedTransactionIndexKey, + TransactionIndex, + }, + Column, + Database, + KvStoreError, + }, + model::BlockHeight, + state::{ + Error, + IterDirection, + }, + tx_pool::TransactionStatus, +}; +use fuel_core_interfaces::{ + common::{ + fuel_storage::{ + StorageInspect, + StorageMutate, + }, + fuel_tx::{ + Bytes32, + Transaction, + }, + fuel_types::Address, + }, + db::Transactions, +}; +use std::{ + borrow::Cow, + ops::Deref, +}; + +impl StorageInspect for Database { + type Error = KvStoreError; + + fn get(&self, key: &Bytes32) -> Result>, KvStoreError> { + Database::get(self, key.as_ref(), Column::Transaction).map_err(Into::into) + } + + fn contains_key(&self, key: &Bytes32) -> Result { + Database::exists(self, key.as_ref(), Column::Transaction).map_err(Into::into) + } +} + +impl StorageMutate for Database { + fn insert( + &mut self, + key: &Bytes32, + value: &Transaction, + ) -> Result, KvStoreError> { + Database::insert(self, key.as_ref(), Column::Transaction, value.clone()) + .map_err(Into::into) + } + + fn remove(&mut self, key: &Bytes32) -> Result, KvStoreError> { + Database::remove(self, key.as_ref(), Column::Transaction).map_err(Into::into) + } +} + +impl Database { + pub fn all_transactions( + &self, + start: Option<&Bytes32>, + direction: Option, + ) -> impl Iterator> + '_ { + let start = start.map(|b| b.as_ref().to_vec()); + self.iter_all::, Transaction>(Column::Transaction, None, start, direction) + .map(|res| res.map(|(_, tx)| tx)) + } + + /// Iterates over a KV mapping of `[address + block height + tx idx] => transaction id`. This + /// allows for efficient lookup of transaction ids associated with an address, sorted by + /// block age and ordering within a block. The cursor tracks the `[block height + tx idx]` for + /// pagination purposes. + pub fn owned_transactions( + &self, + owner: &Address, + start: Option<&OwnedTransactionIndexCursor>, + direction: Option, + ) -> impl Iterator> + '_ + { + let start = start + .map(|cursor| owned_tx_index_key(owner, cursor.block_height, cursor.tx_idx)); + self.iter_all::( + Column::TransactionsByOwnerBlockIdx, + Some(owner.to_vec()), + start, + direction, + ) + .map(|res| res.map(|(key, tx_id)| (key.into(), tx_id))) + } + + pub fn record_tx_id_owner( + &self, + owner: &Address, + block_height: BlockHeight, + tx_idx: TransactionIndex, + tx_id: &Bytes32, + ) -> Result, Error> { + self.insert( + owned_tx_index_key(owner, block_height, tx_idx), + Column::TransactionsByOwnerBlockIdx, + *tx_id, + ) + } + + pub fn update_tx_status( + &self, + tx_id: &Bytes32, + status: TransactionStatus, + ) -> Result, Error> { + self.insert(tx_id, Column::TransactionStatus, status) + } + + pub fn get_tx_status( + &self, + tx_id: &Bytes32, + ) -> Result, Error> { + self.get(&tx_id.deref()[..], Column::TransactionStatus) + } +} + +fn owned_tx_index_key( + owner: &Address, + height: BlockHeight, + tx_idx: TransactionIndex, +) -> Vec { + // generate prefix to enable sorted indexing of transactions by owner + // owner + block_height + tx_idx + let mut key = Vec::with_capacity(40); + key.extend(owner.as_ref()); + key.extend(height.to_bytes()); + key.extend(tx_idx.to_be_bytes()); + key +} diff --git a/fuel-core/src/database/validator_set.rs b/fuel-core/src/database/storage/validator_set.rs similarity index 60% rename from fuel-core/src/database/validator_set.rs rename to fuel-core/src/database/storage/validator_set.rs index db12a4cdab5..5b8aa48f92e 100644 --- a/fuel-core/src/database/validator_set.rs +++ b/fuel-core/src/database/storage/validator_set.rs @@ -1,10 +1,14 @@ use crate::database::{ - columns, + Column, Database, KvStoreError, }; use fuel_core_interfaces::{ - common::fuel_storage::Storage, + common::fuel_storage::{ + StorageInspect, + StorageMutate, + }, + db::ValidatorsSet, model::{ ConsensusId, ValidatorId, @@ -13,15 +17,28 @@ use fuel_core_interfaces::{ }; use std::borrow::Cow; -impl Storage)> for Database { +impl StorageInspect for Database { type Error = KvStoreError; + fn get( + &self, + key: &ValidatorId, + ) -> Result)>>, KvStoreError> { + Database::get(self, key.as_ref(), Column::ValidatorSet).map_err(Into::into) + } + + fn contains_key(&self, key: &ValidatorId) -> Result { + Database::exists(self, key.as_ref(), Column::ValidatorSet).map_err(Into::into) + } +} + +impl StorageMutate for Database { fn insert( &mut self, key: &ValidatorId, value: &(ValidatorStake, Option), ) -> Result)>, KvStoreError> { - Database::insert(self, key.as_ref(), columns::VALIDATOR_SET, *value) + Database::insert(self, key.as_ref(), Column::ValidatorSet, value) .map_err(Into::into) } @@ -29,17 +46,6 @@ impl Storage)> for Database { &mut self, key: &ValidatorId, ) -> Result)>, KvStoreError> { - Database::remove(self, key.as_ref(), columns::VALIDATOR_SET).map_err(Into::into) - } - - fn get( - &self, - key: &ValidatorId, - ) -> Result)>>, KvStoreError> { - Database::get(self, key.as_ref(), columns::VALIDATOR_SET).map_err(Into::into) - } - - fn contains_key(&self, key: &ValidatorId) -> Result { - Database::exists(self, key.as_ref(), columns::VALIDATOR_SET).map_err(Into::into) + Database::remove(self, key.as_ref(), Column::ValidatorSet).map_err(Into::into) } } diff --git a/fuel-core/src/database/transaction.rs b/fuel-core/src/database/transaction.rs index b4bbf1fb843..0eea90981c1 100644 --- a/fuel-core/src/database/transaction.rs +++ b/fuel-core/src/database/transaction.rs @@ -1,124 +1,8 @@ -use crate::{ - database::{ - columns::{ - TRANSACTIONS, - TRANSACTIONS_BY_OWNER_BLOCK_IDX, - TRANSACTION_STATUS, - }, - Database, - KvStoreError, - }, - model::BlockHeight, - state::{ - Error, - IterDirection, - }, - tx_pool::TransactionStatus, -}; -use fuel_core_interfaces::common::{ - fuel_storage::Storage, - fuel_tx::{ - Bytes32, - Transaction, - }, - fuel_types::Address, -}; -use std::{ - borrow::Cow, - ops::Deref, -}; +use fuel_core_interfaces::model::BlockHeight; pub type TransactionIndex = u32; -impl Storage for Database { - type Error = KvStoreError; - - fn insert( - &mut self, - key: &Bytes32, - value: &Transaction, - ) -> Result, KvStoreError> { - Database::insert(self, key.as_ref(), TRANSACTIONS, value.clone()) - .map_err(Into::into) - } - - fn remove(&mut self, key: &Bytes32) -> Result, KvStoreError> { - Database::remove(self, key.as_ref(), TRANSACTIONS).map_err(Into::into) - } - - fn get(&self, key: &Bytes32) -> Result>, KvStoreError> { - Database::get(self, key.as_ref(), TRANSACTIONS).map_err(Into::into) - } - - fn contains_key(&self, key: &Bytes32) -> Result { - Database::exists(self, key.as_ref(), TRANSACTIONS).map_err(Into::into) - } -} - -impl Database { - pub fn all_transactions( - &self, - start: Option<&Bytes32>, - direction: Option, - ) -> impl Iterator> + '_ { - let start = start.map(|b| b.as_ref().to_vec()); - self.iter_all::, Transaction>(TRANSACTIONS, None, start, direction) - .map(|res| res.map(|(_, tx)| tx)) - } - - /// Iterates over a KV mapping of `[address + block height + tx idx] => transaction id`. This - /// allows for efficient lookup of transaction ids associated with an address, sorted by - /// block age and ordering within a block. The cursor tracks the `[block height + tx idx]` for - /// pagination purposes. - pub fn owned_transactions( - &self, - owner: &Address, - start: Option<&OwnedTransactionIndexCursor>, - direction: Option, - ) -> impl Iterator> + '_ - { - let start = start - .map(|cursor| owned_tx_index_key(owner, cursor.block_height, cursor.tx_idx)); - self.iter_all::( - TRANSACTIONS_BY_OWNER_BLOCK_IDX, - Some(owner.to_vec()), - start, - direction, - ) - .map(|res| res.map(|(key, tx_id)| (key.into(), tx_id))) - } - - pub fn record_tx_id_owner( - &self, - owner: &Address, - block_height: BlockHeight, - tx_idx: TransactionIndex, - tx_id: &Bytes32, - ) -> Result, Error> { - self.insert( - owned_tx_index_key(owner, block_height, tx_idx), - TRANSACTIONS_BY_OWNER_BLOCK_IDX, - *tx_id, - ) - } - - pub fn update_tx_status( - &self, - tx_id: &Bytes32, - status: TransactionStatus, - ) -> Result, Error> { - self.insert(tx_id.to_vec(), TRANSACTION_STATUS, status) - } - - pub fn get_tx_status( - &self, - tx_id: &Bytes32, - ) -> Result, Error> { - self.get(&tx_id.deref()[..], TRANSACTION_STATUS) - } -} - -struct OwnedTransactionIndexKey { +pub struct OwnedTransactionIndexKey { block_height: BlockHeight, tx_idx: TransactionIndex, } @@ -176,17 +60,3 @@ impl From for Vec { bytes } } - -fn owned_tx_index_key( - owner: &Address, - height: BlockHeight, - tx_idx: TransactionIndex, -) -> Vec { - // generate prefix to enable sorted indexing of transactions by owner - // owner + block_height + tx_idx - let mut key = Vec::with_capacity(40); - key.extend(owner.as_ref()); - key.extend(height.to_bytes()); - key.extend(tx_idx.to_be_bytes()); - key -} diff --git a/fuel-core/src/executor.rs b/fuel-core/src/executor.rs index 2cf6e1d8d63..c4b97347ffe 100644 --- a/fuel-core/src/executor.rs +++ b/fuel-core/src/executor.rs @@ -1,5 +1,10 @@ use crate::{ database::{ + storage::{ + ContractsLatestUtxo, + FuelBlocks, + Receipts, + }, transaction::TransactionIndex, Database, KvStoreError, @@ -9,7 +14,6 @@ use crate::{ Coin, CoinStatus, FuelBlock, - FuelBlockDb, }, service::Config, tx_pool::TransactionStatus, @@ -19,7 +23,7 @@ use fuel_core_interfaces::{ common::{ fuel_asm::Word, fuel_merkle::binary::in_memory::MerkleTree, - fuel_storage::Storage, + fuel_storage, fuel_tx::{ Address, AssetId, @@ -48,11 +52,20 @@ use fuel_core_interfaces::{ }, }, }, + db::{ + Coins, + Messages, + Transactions, + }, model::{ FuelBlockHeader, Message, }, }; +use fuel_storage::{ + StorageAsMut, + StorageAsRef, +}; use std::{ error::Error as StdError, ops::{ @@ -130,11 +143,13 @@ impl Executor { let mut block_db_transaction = self.database.transaction(); // Insert the current headers (including time, block height, producer into the db tx) - Storage::::insert( - block_db_transaction.deref_mut(), - &Bytes32::zeroed(), // use id of zero as current block - &block.to_db_block(), - )?; + block_db_transaction + .deref_mut() + .storage::() + .insert( + &Bytes32::zeroed(), // use id of zero as current block + &block.to_db_block(), + )?; let mut txs_merkle = MerkleTree::new(); let mut tx_status = vec![]; @@ -144,10 +159,11 @@ impl Executor { let tx_id = tx.id(); // Throw a clear error if the transaction id is a duplicate - if Storage::::contains_key( - block_db_transaction.deref_mut(), - &tx_id, - )? { + if block_db_transaction + .deref_mut() + .storage::() + .contains_key(&tx_id)? + { return Err(Error::TransactionIdCollision(tx_id)) } @@ -247,11 +263,10 @@ impl Executor { } // Store tx into the block db transaction - Storage::::insert( - block_db_transaction.deref_mut(), - &tx_id, - vm_result.tx(), - )?; + block_db_transaction + .deref_mut() + .storage::() + .insert(&tx_id, vm_result.tx())?; // change the spent status of the tx inputs self.spend_inputs( @@ -281,16 +296,14 @@ impl Executor { let reason = vm_result .receipts() .iter() - .find_map(|receipt| { - match receipt { - // Format as `Revert($rA)` - Receipt::Revert { ra, .. } => Some(format!("Revert({})", ra)), - // Display PanicReason e.g. `OutOfGas` - Receipt::Panic { reason, .. } => { - Some(format!("{}", reason.reason())) - } - _ => None, + .find_map(|receipt| match receipt { + // Format as `Revert($rA)` + Receipt::Revert { ra, .. } => Some(format!("Revert({})", ra)), + // Display PanicReason e.g. `OutOfGas` + Receipt::Panic { reason, .. } => { + Some(format!("{}", reason.reason())) } + _ => None, }) .unwrap_or_else(|| format!("{:?}", vm_result.state())); @@ -345,17 +358,16 @@ impl Executor { )?; // cleanup unfinalized headers (block height + time + producer) - Storage::::remove( - block_db_transaction.deref_mut(), - &Bytes32::zeroed(), - )?; + block_db_transaction + .deref_mut() + .storage::() + .remove(&Bytes32::zeroed())?; // insert block into database - Storage::::insert( - block_db_transaction.deref_mut(), - &finalized_block_id, - &block.to_db_block(), - )?; + block_db_transaction + .deref_mut() + .storage::() + .insert(&finalized_block_id, &block.to_db_block())?; block_db_transaction.commit()?; Ok(()) } @@ -371,7 +383,7 @@ impl Executor { match input { Input::CoinSigned { utxo_id, .. } | Input::CoinPredicate { utxo_id, .. } => { - if let Some(coin) = Storage::::get(db, utxo_id)? { + if let Some(coin) = db.storage::().get(utxo_id)? { if coin.status == CoinStatus::Spent { return Err(TransactionValidityError::CoinAlreadySpent( *utxo_id, @@ -389,9 +401,7 @@ impl Executor { Input::Contract { .. } => {} Input::MessageSigned { message_id, .. } | Input::MessagePredicate { message_id, .. } => { - if let Some(message) = - Storage::::get(db, message_id)? - { + if let Some(message) = db.storage::().get(message_id)? { if message.fuel_block_spend.is_some() { return Err(TransactionValidityError::MessageAlreadySpent( *message_id, @@ -489,7 +499,8 @@ impl Executor { .. } => { let block_created = if self.config.utxo_validation { - Storage::::get(db, utxo_id)? + db.storage::() + .get(utxo_id)? .ok_or(Error::TransactionValidity( TransactionValidityError::CoinDoesNotExist(*utxo_id), ))? @@ -499,8 +510,7 @@ impl Executor { Default::default() }; - Storage::::insert( - db, + db.storage::().insert( utxo_id, &Coin { owner: *owner, @@ -533,7 +543,8 @@ impl Executor { .. } => { let da_height = if self.config.utxo_validation { - Storage::::get(db, message_id)? + db.storage::() + .get(message_id)? .ok_or(Error::TransactionValidity( TransactionValidityError::MessageDoesNotExist( *message_id, @@ -545,8 +556,7 @@ impl Executor { Default::default() }; - Storage::::insert( - db, + db.storage::().insert( message_id, &Message { da_height, @@ -605,7 +615,7 @@ impl Executor { } = input { let maybe_utxo_id = - Storage::::get(db, contract_id)?; + db.storage::().get(contract_id)?; let expected_utxo_id = if self.config.utxo_validation { maybe_utxo_id .ok_or(Error::ContractUtxoMissing(*contract_id))? @@ -680,7 +690,8 @@ impl Executor { if let Some(Input::Contract { contract_id, .. }) = tx.inputs().get(*input_idx as usize) { - Storage::::insert(db, contract_id, &utxo_id)?; + db.storage::() + .insert(contract_id, &utxo_id)?; } else { return Err(Error::TransactionValidity( TransactionValidityError::InvalidContractInputIndex(utxo_id), @@ -715,7 +726,8 @@ impl Executor { db, )?, Output::ContractCreated { contract_id, .. } => { - Storage::::insert(db, contract_id, &utxo_id)?; + db.storage::() + .insert(contract_id, &utxo_id)?; } } } @@ -743,7 +755,7 @@ impl Executor { block_created: fuel_height.into(), }; - if Storage::::insert(db, &utxo_id, &coin)?.is_some() { + if db.storage::().insert(&utxo_id, &coin)?.is_some() { return Err(Error::OutputAlreadyExists) } } @@ -757,7 +769,9 @@ impl Executor { receipts: &[Receipt], db: &mut Database, ) -> Result<(), Error> { - if Storage::>::insert(db, tx_id, &Vec::from(receipts))? + if db + .storage::() + .insert(tx_id, &Vec::from(receipts))? .is_some() { return Err(Error::OutputAlreadyExists) @@ -1173,9 +1187,9 @@ mod tests { block_created, }; - let mut db = Database::default(); + let db = &mut Database::default(); // initialize database with coin that was already spent - Storage::::insert(&mut db, &spent_utxo_id, &coin).unwrap(); + db.storage::().insert(&spent_utxo_id, &coin).unwrap(); // create an input referring to a coin that is already spent let input = Input::coin_signed( @@ -1445,7 +1459,7 @@ mod tests { .build() .into(); - let db = Database::default(); + let db = &Database::default(); let executor = Executor { database: db.clone(), config: Config::local_node(), @@ -1462,12 +1476,11 @@ mod tests { .unwrap(); // assert the tx coin is spent - let coin = Storage::::get( - &db, - block.transactions[0].inputs()[0].utxo_id().unwrap(), - ) - .unwrap() - .unwrap(); + let coin = db + .storage::() + .get(block.transactions[0].inputs()[0].utxo_id().unwrap()) + .unwrap() + .unwrap(); assert_eq!(coin.status, CoinStatus::Spent); } @@ -1495,7 +1508,7 @@ mod tests { asset_id: Default::default(), }) .finalize(); - let mut db = Database::default(); + let db = &mut Database::default(); // insert coin into state if let Input::CoinSigned { @@ -1513,19 +1526,19 @@ mod tests { .. } = tx.inputs()[0] { - Storage::::insert( - &mut db, - &utxo_id, - &Coin { - owner, - amount, - asset_id, - maturity: Default::default(), - status: CoinStatus::Unspent, - block_created: starting_block, - }, - ) - .unwrap(); + db.storage::() + .insert( + &utxo_id, + &Coin { + owner, + amount, + asset_id, + maturity: Default::default(), + status: CoinStatus::Unspent, + block_created: starting_block, + }, + ) + .unwrap(); } let executor = Executor { @@ -1551,12 +1564,11 @@ mod tests { .unwrap(); // assert the tx coin is spent - let coin = Storage::::get( - &db, - block.transactions[0].inputs()[0].utxo_id().unwrap(), - ) - .unwrap() - .unwrap(); + let coin = db + .storage::() + .get(block.transactions[0].inputs()[0].utxo_id().unwrap()) + .unwrap() + .unwrap(); assert_eq!(coin.status, CoinStatus::Spent); // assert block created from coin before spend is still intact (only a concern when utxo-validation is enabled) assert_eq!(coin.block_created, starting_block) @@ -1781,7 +1793,7 @@ mod tests { .into(); let tx2_id = tx2.id(); - let database = Database::default(); + let database = &Database::default(); let executor = Executor { database: database.clone(), config: Config::local_node(), @@ -1802,8 +1814,7 @@ mod tests { let id = fuel_tx::UtxoId::new(tx2_id, idx as u8); match output { Output::Change { .. } | Output::Variable { .. } | Output::Coin { .. } => { - let maybe_utxo = - Storage::::get(&database, &id).unwrap(); + let maybe_utxo = database.storage::().get(&id).unwrap(); assert!(maybe_utxo.is_some()); let utxo = maybe_utxo.unwrap(); assert!(utxo.amount > 0) @@ -1829,7 +1840,7 @@ mod tests { .into(); let tx_id = tx.id(); - let database = Database::default(); + let database = &Database::default(); let executor = Executor { database: database.clone(), config: Config::local_node(), @@ -1847,7 +1858,7 @@ mod tests { for idx in 0..2 { let id = UtxoId::new(tx_id, idx); - let maybe_utxo = Storage::::get(&database, &id).unwrap(); + let maybe_utxo = database.storage::().get(&id).unwrap(); assert!(maybe_utxo.is_none()); } } @@ -2064,21 +2075,22 @@ mod tests { }; // setup db with coin to spend - let mut database = Database::default(); + let database = &mut &mut Database::default(); let coin_input = &tx.inputs()[0]; - Storage::::insert( - &mut database, - coin_input.utxo_id().unwrap(), - &Coin { - owner: *coin_input.input_owner().unwrap(), - amount: coin_input.amount().unwrap(), - asset_id: *coin_input.asset_id().unwrap(), - maturity: (coin_input.maturity().unwrap()).into(), - block_created: 0u64.into(), - status: CoinStatus::Unspent, - }, - ) - .unwrap(); + database + .storage::() + .insert( + coin_input.utxo_id().unwrap(), + &Coin { + owner: *coin_input.input_owner().unwrap(), + amount: coin_input.amount().unwrap(), + asset_id: *coin_input.asset_id().unwrap(), + maturity: (coin_input.maturity().unwrap()).into(), + block_created: 0u64.into(), + status: CoinStatus::Unspent, + }, + ) + .unwrap(); // make executor with db let executor = Executor { @@ -2094,7 +2106,9 @@ mod tests { .await .unwrap(); - let receipts = Storage::>::get(&database, &tx.id()) + let receipts = database + .storage::() + .get(&tx.id()) .unwrap() .unwrap(); assert_eq!(block_height as u64, receipts[0].val().unwrap()); @@ -2136,21 +2150,22 @@ mod tests { }; // setup db with coin to spend - let mut database = Database::default(); + let database = &mut &mut Database::default(); let coin_input = &tx.inputs()[0]; - Storage::::insert( - &mut database, - coin_input.utxo_id().unwrap(), - &Coin { - owner: *coin_input.input_owner().unwrap(), - amount: coin_input.amount().unwrap(), - asset_id: *coin_input.asset_id().unwrap(), - maturity: (coin_input.maturity().unwrap()).into(), - block_created: 0u64.into(), - status: CoinStatus::Unspent, - }, - ) - .unwrap(); + database + .storage::() + .insert( + coin_input.utxo_id().unwrap(), + &Coin { + owner: *coin_input.input_owner().unwrap(), + amount: coin_input.amount().unwrap(), + asset_id: *coin_input.asset_id().unwrap(), + maturity: (coin_input.maturity().unwrap()).into(), + block_created: 0u64.into(), + status: CoinStatus::Unspent, + }, + ) + .unwrap(); // make executor with db let executor = Executor { @@ -2166,7 +2181,9 @@ mod tests { .await .unwrap(); - let receipts = Storage::>::get(&database, &tx.id()) + let receipts = database + .storage::() + .get(&tx.id()) .unwrap() .unwrap(); diff --git a/fuel-core/src/schema/balance.rs b/fuel-core/src/schema/balance.rs index bda2010c7b0..e3e00ce0dd8 100644 --- a/fuel-core/src/schema/balance.rs +++ b/fuel-core/src/schema/balance.rs @@ -3,10 +3,7 @@ use crate::{ Database, KvStoreError, }, - model::{ - Coin as CoinModel, - CoinStatus, - }, + model::CoinStatus, schema::scalars::{ Address, AssetId, @@ -29,10 +26,13 @@ use async_graphql::{ InputObject, Object, }; -use fuel_core_interfaces::common::{ - fuel_storage::Storage, - fuel_tx, - fuel_types, +use fuel_core_interfaces::{ + common::{ + fuel_storage::StorageAsRef, + fuel_tx, + fuel_types, + }, + db::Coins, }; use itertools::Itertools; @@ -80,7 +80,8 @@ impl BalanceQuery { .owned_coins(owner.into(), None, None) .map(|res| -> Result<_, Error> { let id = res?; - Storage::::get(db, &id) + db.storage::() + .get(&id) .transpose() .ok_or(KvStoreError::NotFound)? .map_err(Into::into) @@ -123,7 +124,8 @@ impl BalanceQuery { .owned_coins(filter.owner.into(), None, None) .map(|res| -> Result<_, Error> { let id = res?; - Storage::::get(db, &id) + db.storage::() + .get(&id) .transpose() .ok_or(KvStoreError::NotFound)? .map_err(Into::into) diff --git a/fuel-core/src/schema/block.rs b/fuel-core/src/schema/block.rs index 05e821e7bcf..3eb4854a3fa 100644 --- a/fuel-core/src/schema/block.rs +++ b/fuel-core/src/schema/block.rs @@ -1,5 +1,6 @@ use crate::{ database::{ + storage::FuelBlocks, Database, KvStoreError, }, @@ -38,10 +39,12 @@ use chrono::{ DateTime, Utc, }; -use fuel_core_interfaces::common::{ - fuel_storage::Storage, - fuel_tx, - fuel_types, +use fuel_core_interfaces::{ + common::{ + fuel_storage::StorageAsRef, + fuel_types, + }, + db::Transactions, }; use itertools::Itertools; use std::{ @@ -73,7 +76,8 @@ impl Block { .iter() .map(|tx_id| { Ok(Transaction( - Storage::::get(&db, tx_id) + db.storage::() + .get(tx_id) .and_then(|v| v.ok_or(KvStoreError::NotFound))? .into_owned(), )) @@ -125,7 +129,9 @@ impl BlockQuery { } }; - let block = Storage::::get(db, &id)? + let block = db + .storage::() + .get(&id)? .map(|b| Block(b.into_owned())); Ok(block) } @@ -202,7 +208,8 @@ impl BlockQuery { let blocks: Vec> = blocks .iter() .map(|(_, id)| { - Storage::::get(&db, id) + db.storage::() + .get(id) .transpose() .ok_or(KvStoreError::NotFound)? }) diff --git a/fuel-core/src/schema/chain.rs b/fuel-core/src/schema/chain.rs index cd2aae5734e..f44bf8bffee 100644 --- a/fuel-core/src/schema/chain.rs +++ b/fuel-core/src/schema/chain.rs @@ -1,6 +1,8 @@ use crate::{ - database::Database, - model::FuelBlockDb, + database::{ + storage::FuelBlocks, + Database, + }, schema::{ block::Block, scalars::U64, @@ -12,9 +14,8 @@ use async_graphql::{ Object, }; use fuel_core_interfaces::common::{ - fuel_storage::Storage, + fuel_storage::StorageAsRef, fuel_tx, - fuel_types, }; pub const DEFAULT_NAME: &str = "Fuel.testnet"; @@ -92,8 +93,7 @@ impl ChainInfo { let db = ctx.data_unchecked::().clone(); let height = db.get_block_height()?.unwrap_or_default(); let id = db.get_block_id(height)?.unwrap_or_default(); - let block = Storage::::get(&db, &id)? - .unwrap_or_default(); + let block = db.storage::().get(&id)?.unwrap_or_default(); Ok(Block(block.into_owned())) } diff --git a/fuel-core/src/schema/coin.rs b/fuel-core/src/schema/coin.rs index 76844fbf7ef..d60c41aee92 100644 --- a/fuel-core/src/schema/coin.rs +++ b/fuel-core/src/schema/coin.rs @@ -31,9 +31,10 @@ use async_graphql::{ }; use fuel_core_interfaces::{ common::{ - fuel_storage::Storage, + fuel_storage::StorageAsRef, fuel_tx, }, + db::Coins, model::{ Coin as CoinModel, CoinStatus as CoinStatusModel, @@ -109,7 +110,9 @@ impl CoinQuery { ) -> async_graphql::Result> { let utxo_id = utxo_id.0; let db = ctx.data_unchecked::().clone(); - let block = Storage::::get(&db, &utxo_id)? + let block = db + .storage::() + .get(&utxo_id)? .map(|coin| Coin(utxo_id, coin.into_owned())); Ok(block) } @@ -191,7 +194,8 @@ impl CoinQuery { let coins: Vec = coins .into_iter() .map(|id| { - Storage::::get(db, &id) + db.storage::() + .get(&id) .transpose() .ok_or(KvStoreError::NotFound)? .map(|coin| Coin(id, coin.into_owned())) diff --git a/fuel-core/src/schema/contract.rs b/fuel-core/src/schema/contract.rs index 13b87abee1d..01b046dfcbd 100644 --- a/fuel-core/src/schema/contract.rs +++ b/fuel-core/src/schema/contract.rs @@ -24,12 +24,14 @@ use async_graphql::{ InputObject, Object, }; -use fuel_core_interfaces::common::{ - fuel_storage::Storage, - fuel_tx, - fuel_types, - fuel_vm, - fuel_vm::prelude::Contract as FuelVmContract, +use fuel_core_interfaces::{ + common::{ + fuel_storage::StorageAsRef, + fuel_tx, + fuel_types, + fuel_vm, + }, + db::ContractsRawCode, }; use std::iter::IntoIterator; @@ -49,10 +51,11 @@ impl Contract { async fn bytecode(&self, ctx: &Context<'_>) -> async_graphql::Result { let db = ctx.data_unchecked::().clone(); - let contract = - Storage::::get(&db, &self.0)? - .ok_or(KvStoreError::NotFound)? - .into_owned(); + let contract = db + .storage::() + .get(&self.0)? + .ok_or(KvStoreError::NotFound)? + .into_owned(); Ok(HexString(contract.into())) } async fn salt(&self, ctx: &Context<'_>) -> async_graphql::Result { @@ -84,8 +87,7 @@ impl ContractQuery { ) -> async_graphql::Result> { let id: fuel_types::ContractId = id.0; let db = ctx.data_unchecked::().clone(); - let contract_exists = - Storage::::contains_key(&db, &id)?; + let contract_exists = db.storage::().contains_key(&id)?; if !contract_exists { return Ok(None) } diff --git a/fuel-core/src/schema/message.rs b/fuel-core/src/schema/message.rs index bee7cc45517..51b1a4f5569 100644 --- a/fuel-core/src/schema/message.rs +++ b/fuel-core/src/schema/message.rs @@ -20,10 +20,13 @@ use async_graphql::{ }; use fuel_core_interfaces::{ common::{ - fuel_storage::Storage, + fuel_storage::StorageAsRef, fuel_types, }, - db::KvStoreError, + db::{ + KvStoreError, + Messages, + }, model, }; use itertools::Itertools; @@ -131,12 +134,11 @@ impl MessageQuery { .iter() .take(records_to_fetch) .map(|msg_id| { - Storage::::get( - &db, msg_id, - ) - .transpose() - .ok_or(KvStoreError::NotFound)? - .map(|f| f.into_owned()) + db.storage::() + .get(msg_id) + .transpose() + .ok_or(KvStoreError::NotFound)? + .map(|f| f.into_owned()) }) .try_collect()?; (messages, has_next_page, started.is_some()) diff --git a/fuel-core/src/schema/tx.rs b/fuel-core/src/schema/tx.rs index c0693e7ce03..af8c2b7fbc2 100644 --- a/fuel-core/src/schema/tx.rs +++ b/fuel-core/src/schema/tx.rs @@ -1,14 +1,15 @@ use crate::{ database::{ + storage::{ + FuelBlocks, + Receipts, + }, transaction::OwnedTransactionIndexCursor, Database, KvStoreError, }, executor::Executor, - model::{ - BlockHeight, - FuelBlockDb, - }, + model::BlockHeight, schema::scalars::{ Address, Bytes32, @@ -32,15 +33,12 @@ use async_graphql::{ }; use fuel_core_interfaces::{ common::{ - fuel_storage::Storage, - fuel_tx::{ - Bytes32 as FuelBytes32, - Receipt as FuelReceipt, - Transaction as FuelTx, - }, + fuel_storage::StorageAsRef, + fuel_tx::Transaction as FuelTx, fuel_types, fuel_vm::prelude::Deserializable, }, + db::Transactions, txpool::TxPoolMpsc, }; use fuel_txpool::Service as TxPoolService; @@ -85,7 +83,9 @@ impl TxQuery { if let Ok(Some(transaction)) = receiver.await { Ok(Some(Transaction((transaction.tx().deref()).clone()))) } else { - Ok(Storage::::get(db, &id)? + Ok(db + .storage::() + .get(&id)? .map(|tx| Transaction(tx.into_owned()))) } } @@ -147,7 +147,7 @@ impl TxQuery { let txs = all_block_ids .flat_map(|block| { block.map(|(block_height, block_id)| { - Storage::::get(db, &block_id) + db.storage::().get(&block_id) .transpose() .ok_or(KvStoreError::NotFound)? .map(|fuel_block| { @@ -180,7 +180,7 @@ impl TxQuery { .iter() .take(records_to_fetch) .map(|(tx_id, block_height)| -> Result<(Cow, &BlockHeight), KvStoreError> { - let tx = Storage::::get(db, tx_id) + let tx = db.storage::().get(tx_id) .transpose() .ok_or(KvStoreError::NotFound)?; @@ -279,11 +279,11 @@ impl TxQuery { .take(records_to_fetch) .map(|res| { res.and_then(|(cursor, tx_id)| { - let tx = Storage::::get( - db, &tx_id, - )? - .ok_or(KvStoreError::NotFound)? - .into_owned(); + let tx = db + .storage::() + .get(&tx_id)? + .ok_or(KvStoreError::NotFound)? + .into_owned(); Ok((cursor, tx)) }) }); @@ -341,9 +341,11 @@ impl TxMutation { }; executor.submit_txs(vec![Arc::new(tx)]).await?; // get receipts from db transaction - let receipts = - Storage::>::get(transaction.deref(), &id)? - .unwrap_or_default(); + let receipts = transaction + .deref() + .storage::() + .get(&id)? + .unwrap_or_default(); Ok(receipts.iter().map(Into::into).collect()) } diff --git a/fuel-core/src/schema/tx/types.rs b/fuel-core/src/schema/tx/types.rs index 77eb0ef3652..47c854099dd 100644 --- a/fuel-core/src/schema/tx/types.rs +++ b/fuel-core/src/schema/tx/types.rs @@ -4,8 +4,13 @@ use super::{ receipt::Receipt, }; use crate::{ - database::Database, - model::FuelBlockDb, + database::{ + storage::{ + FuelBlocks, + Receipts, + }, + Database, + }, schema::{ block::Block, contract::Contract, @@ -32,7 +37,7 @@ use chrono::{ }; use fuel_core_interfaces::{ common::{ - fuel_storage::Storage, + fuel_storage::StorageAsRef, fuel_tx, fuel_types, fuel_types::bytes::SerializableVec, @@ -117,7 +122,9 @@ pub struct SuccessStatus { impl SuccessStatus { async fn block(&self, ctx: &Context<'_>) -> async_graphql::Result { let db = ctx.data_unchecked::(); - let block = Storage::::get(db, &self.block_id)? + let block = db + .storage::() + .get(&self.block_id)? .ok_or(KvStoreError::NotFound)? .into_owned(); let block = Block(block); @@ -144,7 +151,9 @@ pub struct FailureStatus { impl FailureStatus { async fn block(&self, ctx: &Context<'_>) -> async_graphql::Result { let db = ctx.data_unchecked::(); - let block = Storage::::get(db, &self.block_id)? + let block = db + .storage::() + .get(&self.block_id)? .ok_or(KvStoreError::NotFound)? .into_owned(); let block = Block(block); @@ -274,8 +283,7 @@ impl Transaction { ctx: &Context<'_>, ) -> async_graphql::Result>> { let db = ctx.data_unchecked::(); - let receipts = - Storage::>::get(db, &self.0.id())?; + let receipts = db.storage::().get(&self.0.id())?; Ok(receipts.map(|receipts| receipts.iter().cloned().map(Receipt).collect())) } diff --git a/fuel-core/src/service/genesis.rs b/fuel-core/src/service/genesis.rs index 761b7f841c9..cd0c9d822d4 100644 --- a/fuel-core/src/service/genesis.rs +++ b/fuel-core/src/service/genesis.rs @@ -3,7 +3,10 @@ use crate::{ ContractConfig, StateConfig, }, - database::Database, + database::{ + storage::ContractsLatestUtxo, + Database, + }, service::{ config::Config, FuelService, @@ -12,24 +15,25 @@ use crate::{ use anyhow::Result; use fuel_core_interfaces::{ common::{ - fuel_storage::{ - MerkleStorage, - Storage, - }, + fuel_storage::StorageAsMut, fuel_tx::{ Contract, - MessageId, UtxoId, }, fuel_types::{ bytes::WORD_SIZE, - AssetId, Bytes32, ContractId, - Salt, - Word, }, }, + db::{ + Coins, + ContractsAssets, + ContractsInfo, + ContractsRawCode, + ContractsState, + Messages, + }, model::{ Coin, CoinStatus, @@ -100,7 +104,7 @@ impl FuelService { block_created: coin.block_created.unwrap_or_default(), }; - let _ = Storage::::insert(db, &utxo_id, &coin)?; + let _ = db.storage::().insert(&utxo_id, &coin)?; } } Ok(()) @@ -117,16 +121,14 @@ impl FuelService { let contract_id = contract.id(&salt, &root, &Contract::default_state_root()); // insert contract code - let _ = - Storage::::insert(db, &contract_id, &contract)?; + let _ = db + .storage::() + .insert(&contract_id, contract.as_ref())?; // insert contract root - let _ = Storage::::insert( - db, - &contract_id, - &(salt, root), - )?; - let _ = Storage::::insert( - db, + let _ = db + .storage::() + .insert(&contract_id, &(salt, root))?; + let _ = db.storage::().insert( &contract_id, &UtxoId::new( // generated transaction id([0..[out_index/255]]) @@ -160,12 +162,8 @@ impl FuelService { // insert state related to contract if let Some(contract_state) = &contract.state { for (key, value) in contract_state { - MerkleStorage::::insert( - db, - contract_id, - key, - value, - )?; + db.storage::() + .insert(&(contract_id, key), value)?; } } Ok(()) @@ -185,7 +183,7 @@ impl FuelService { fuel_block_spend: None, }; - Storage::::insert(db, &message.id(), &message)?; + db.storage::().insert(&message.id(), &message)?; } } @@ -200,12 +198,8 @@ impl FuelService { // insert balances related to contract if let Some(balances) = &contract.balances { for (key, value) in balances { - MerkleStorage::::insert( - db, - contract_id, - key, - value, - )?; + db.storage::() + .insert(&(contract_id, key), value)?; } } Ok(()) @@ -214,9 +208,8 @@ impl FuelService { #[cfg(test)] mod tests { - use std::vec; - use super::*; + use crate::{ chain_config::{ ChainConfig, @@ -231,14 +224,16 @@ mod tests { use fuel_core_interfaces::{ common::{ fuel_asm::Opcode, + fuel_storage::StorageAsRef, fuel_types::{ Address, AssetId, - Word, }, }, + db::Coins, model::Message, }; + use fuel_crypto::fuel_types::Salt; use itertools::Itertools; use rand::{ rngs::StdRng, @@ -246,6 +241,7 @@ mod tests { RngCore, SeedableRng, }; + use std::vec; #[tokio::test] async fn config_initializes_chain_name() { @@ -428,7 +424,9 @@ mod tests { .await .unwrap(); - let ret = MerkleStorage::::get(&db, &id, &test_key) + let ret = db + .storage::() + .get(&(&id, &test_key)) .unwrap() .expect("Expect a state entry to exist with test_key") .into_owned(); @@ -456,13 +454,15 @@ mod tests { ..Default::default() }); - let db = Database::default(); + let db = &Database::default(); - FuelService::initialize_state(&config, &db).unwrap(); + FuelService::initialize_state(&config, db).unwrap(); let expected_msg: Message = msg.into(); - let ret_msg = Storage::::get(&db, &expected_msg.id()) + let ret_msg = db + .storage::() + .get(&expected_msg.id()) .unwrap() .unwrap() .into_owned(); @@ -503,11 +503,12 @@ mod tests { .await .unwrap(); - let ret = - MerkleStorage::::get(&db, &id, &test_asset_id) - .unwrap() - .expect("Expected a balance to be present") - .into_owned(); + let ret = db + .storage::>() + .get(&(&id, &test_asset_id)) + .unwrap() + .expect("Expected a balance to be present") + .into_owned(); assert_eq!(test_balance, ret) } @@ -516,7 +517,8 @@ mod tests { db.owned_coins(owner, None, None) .map(|r| { r.and_then(|coin_id| { - Storage::::get(db, &coin_id) + db.storage::() + .get(&coin_id) .map_err(Into::into) .map(|v| (coin_id, v.unwrap().into_owned())) }) diff --git a/fuel-core/src/state.rs b/fuel-core/src/state.rs index e0728710eb0..271b1cbbda9 100644 --- a/fuel-core/src/state.rs +++ b/fuel-core/src/state.rs @@ -1,10 +1,15 @@ -use crate::state::in_memory::transaction::MemoryTransactionView; +use crate::{ + database::Column, + state::in_memory::transaction::MemoryTransactionView, +}; use std::{ fmt::Debug, marker::PhantomData, sync::Arc, }; +pub use fuel_core_interfaces::db::Error; + pub type Result = core::result::Result; pub type DataSource = Arc; pub type ColumnId = u32; @@ -17,7 +22,7 @@ pub struct MultiKey, K2: AsRef<[u8]>> { } impl, K2: AsRef<[u8]>> MultiKey { - pub fn new(key: (K1, K2)) -> Self { + pub fn new(key: &(K1, K2)) -> Self { Self { _marker_1: Default::default(), _marker_2: Default::default(), @@ -47,18 +52,13 @@ impl, K2: AsRef<[u8]>> From> for Vec { pub type KVItem = Result<(Vec, Vec)>; pub trait KeyValueStore { - fn get(&self, key: &[u8], column: ColumnId) -> Result>>; - fn put( - &self, - key: Vec, - column: ColumnId, - value: Vec, - ) -> Result>>; - fn delete(&self, key: &[u8], column: ColumnId) -> Result>>; - fn exists(&self, key: &[u8], column: ColumnId) -> Result; + fn get(&self, key: &[u8], column: Column) -> Result>>; + fn put(&self, key: &[u8], column: Column, value: Vec) -> Result>>; + fn delete(&self, key: &[u8], column: Column) -> Result>>; + fn exists(&self, key: &[u8], column: Column) -> Result; fn iter_all( &self, - column: ColumnId, + column: Column, prefix: Option>, start: Option>, direction: IterDirection, @@ -77,8 +77,6 @@ impl Default for IterDirection { } } -pub use fuel_core_interfaces::db::Error; - pub trait BatchOperations: KeyValueStore { fn batch_write( &self, @@ -88,7 +86,7 @@ pub trait BatchOperations: KeyValueStore { match entry { // TODO: error handling WriteOperation::Insert(key, column, value) => { - let _ = self.put(key, column, value); + let _ = self.put(&key, column, value); } WriteOperation::Remove(key, column) => { let _ = self.delete(&key, column); @@ -101,8 +99,8 @@ pub trait BatchOperations: KeyValueStore { #[derive(Debug)] pub enum WriteOperation { - Insert(Vec, ColumnId, Vec), - Remove(Vec, ColumnId), + Insert(Vec, Column, Vec), + Remove(Vec, Column), } pub trait Transaction { diff --git a/fuel-core/src/state/in_memory.rs b/fuel-core/src/state/in_memory.rs index f8140f08a3b..c7d21b922c7 100644 --- a/fuel-core/src/state/in_memory.rs +++ b/fuel-core/src/state/in_memory.rs @@ -1,15 +1,18 @@ -use crate::state::ColumnId; +use crate::{ + database::Column, + state::ColumnId, +}; pub mod memory_store; pub mod transaction; -pub(crate) fn column_key(key: &[u8], column: ColumnId) -> Vec { - let mut ck = column.to_be_bytes().to_vec(); +pub(crate) fn column_key(key: &[u8], column: Column) -> Vec { + let mut ck = (column as ColumnId).to_be_bytes().to_vec(); ck.extend_from_slice(key); ck } -pub(crate) fn is_column(column_key: &[u8], column: ColumnId) -> bool { - let column_bytes = column.to_be_bytes(); +pub(crate) fn is_column(column_key: &[u8], column: Column) -> bool { + let column_bytes = (column as ColumnId).to_be_bytes(); column_key[..column_bytes.len()] == column_bytes } diff --git a/fuel-core/src/state/in_memory/memory_store.rs b/fuel-core/src/state/in_memory/memory_store.rs index e23fef4a306..36f7887f2d9 100644 --- a/fuel-core/src/state/in_memory/memory_store.rs +++ b/fuel-core/src/state/in_memory/memory_store.rs @@ -1,14 +1,17 @@ -use crate::state::{ - in_memory::{ - column_key, - is_column, +use crate::{ + database::Column, + state::{ + in_memory::{ + column_key, + is_column, + }, + BatchOperations, + ColumnId, + IterDirection, + KeyValueStore, + Result, + TransactableStorage, }, - BatchOperations, - ColumnId, - IterDirection, - KeyValueStore, - Result, - TransactableStorage, }; use itertools::Itertools; use std::{ @@ -24,7 +27,7 @@ pub struct MemoryStore { } impl KeyValueStore for MemoryStore { - fn get(&self, key: &[u8], column: ColumnId) -> Result>> { + fn get(&self, key: &[u8], column: Column) -> Result>> { Ok(self .inner .lock() @@ -33,20 +36,15 @@ impl KeyValueStore for MemoryStore { .cloned()) } - fn put( - &self, - key: Vec, - column: ColumnId, - value: Vec, - ) -> Result>> { + fn put(&self, key: &[u8], column: Column, value: Vec) -> Result>> { Ok(self .inner .lock() .expect("poisoned") - .insert(column_key(&key, column), value)) + .insert(column_key(key, column), value)) } - fn delete(&self, key: &[u8], column: ColumnId) -> Result>> { + fn delete(&self, key: &[u8], column: Column) -> Result>> { Ok(self .inner .lock() @@ -54,7 +52,7 @@ impl KeyValueStore for MemoryStore { .remove(&column_key(key, column))) } - fn exists(&self, key: &[u8], column: ColumnId) -> Result { + fn exists(&self, key: &[u8], column: Column) -> Result { Ok(self .inner .lock() @@ -64,7 +62,7 @@ impl KeyValueStore for MemoryStore { fn iter_all( &self, - column: ColumnId, + column: Column, prefix: Option>, start: Option>, direction: IterDirection, diff --git a/fuel-core/src/state/in_memory/transaction.rs b/fuel-core/src/state/in_memory/transaction.rs index 451e343c80d..c1a3d598cde 100644 --- a/fuel-core/src/state/in_memory/transaction.rs +++ b/fuel-core/src/state/in_memory/transaction.rs @@ -1,19 +1,21 @@ -use crate::state::{ - in_memory::{ - column_key, - memory_store::MemoryStore, +use crate::{ + database::Column, + state::{ + in_memory::{ + column_key, + memory_store::MemoryStore, + }, + BatchOperations, + DataSource, + IterDirection, + KeyValueStore, + Result, + TransactableStorage, + Transaction, + TransactionError, + TransactionResult, + WriteOperation, }, - BatchOperations, - ColumnId, - DataSource, - IterDirection, - KeyValueStore, - Result, - TransactableStorage, - Transaction, - TransactionError, - TransactionResult, - WriteOperation, }; use itertools::{ EitherOrBoth, @@ -59,7 +61,7 @@ impl MemoryTransactionView { } impl KeyValueStore for MemoryTransactionView { - fn get(&self, key: &[u8], column: ColumnId) -> Result>> { + fn get(&self, key: &[u8], column: Column) -> Result>> { // try to fetch data from View layer if any changes to the key if self .changes @@ -74,27 +76,22 @@ impl KeyValueStore for MemoryTransactionView { } } - fn put( - &self, - key: Vec, - column: ColumnId, - value: Vec, - ) -> Result>> { - let k = column_key(&key, column); + fn put(&self, key: &[u8], column: Column, value: Vec) -> Result>> { + let k = column_key(key, column); let contained_key = self.changes.lock().expect("poisoned lock").contains_key(&k); - self.changes.lock().expect("poisoned lock").insert( - k, - WriteOperation::Insert(key.clone(), column, value.clone()), - ); - let res = self.view_layer.put(key.clone(), column, value); + self.changes + .lock() + .expect("poisoned lock") + .insert(k, WriteOperation::Insert(key.into(), column, value.clone())); + let res = self.view_layer.put(key, column, value); if contained_key { res } else { - self.data_source.get(&key, column) + self.data_source.get(key, column) } } - fn delete(&self, key: &[u8], column: ColumnId) -> Result>> { + fn delete(&self, key: &[u8], column: Column) -> Result>> { let k = column_key(key, column); let contained_key = self.changes.lock().expect("poisoned lock").contains_key(&k); self.changes @@ -109,7 +106,7 @@ impl KeyValueStore for MemoryTransactionView { } } - fn exists(&self, key: &[u8], column: ColumnId) -> Result { + fn exists(&self, key: &[u8], column: Column) -> Result { let k = column_key(key, column); if self.changes.lock().expect("poisoned lock").contains_key(&k) { self.view_layer.exists(key, column) @@ -120,7 +117,7 @@ impl KeyValueStore for MemoryTransactionView { fn iter_all( &self, - column: ColumnId, + column: Column, prefix: Option>, start: Option>, direction: IterDirection, @@ -210,9 +207,9 @@ mod tests { let store = Arc::new(MemoryStore::default()); let view = MemoryTransactionView::new(store); let key = vec![0xA, 0xB, 0xC]; - view.put(key.clone(), 0, vec![1, 2, 3]).unwrap(); + view.put(&key, Column::Metadata, vec![1, 2, 3]).unwrap(); // test - let ret = view.get(&key, 0).unwrap(); + let ret = view.get(&key, Column::Metadata).unwrap(); // verify assert_eq!(ret, Some(vec![1, 2, 3])) } @@ -222,10 +219,10 @@ mod tests { // setup let store = Arc::new(MemoryStore::default()); let key = vec![0xA, 0xB, 0xC]; - store.put(key.clone(), 0, vec![1, 2, 3]).unwrap(); + store.put(&key, Column::Metadata, vec![1, 2, 3]).unwrap(); let view = MemoryTransactionView::new(store); // test - let ret = view.get(&key, 0).unwrap(); + let ret = view.get(&key, Column::Metadata).unwrap(); // verify assert_eq!(ret, Some(vec![1, 2, 3])) } @@ -235,12 +232,12 @@ mod tests { // setup let store = Arc::new(MemoryStore::default()); let key = vec![0xA, 0xB, 0xC]; - store.put(key.clone(), 0, vec![1, 2, 3]).unwrap(); + store.put(&key, Column::Metadata, vec![1, 2, 3]).unwrap(); let view = MemoryTransactionView::new(store.clone()); - view.delete(&key, 0).unwrap(); + view.delete(&key, Column::Metadata).unwrap(); // test - let ret = view.get(&key, 0).unwrap(); - let original = store.get(&key, 0).unwrap(); + let ret = view.get(&key, Column::Metadata).unwrap(); + let original = store.get(&key, Column::Metadata).unwrap(); // verify assert_eq!(ret, None); // also ensure the original value is still intact and we aren't just passing @@ -253,9 +250,11 @@ mod tests { // setup let store = Arc::new(MemoryStore::default()); let view = MemoryTransactionView::new(store); - let _ = view.put(vec![0xA, 0xB, 0xC], 0, vec![1, 2, 3]); + let _ = view.put(&[0xA, 0xB, 0xC], Column::Metadata, vec![1, 2, 3]); // test - let ret = view.put(vec![0xA, 0xB, 0xC], 0, vec![2, 4, 6]).unwrap(); + let ret = view + .put(&[0xA, 0xB, 0xC], Column::Metadata, vec![2, 4, 6]) + .unwrap(); // verify assert_eq!(ret, Some(vec![1, 2, 3])) } @@ -266,10 +265,10 @@ mod tests { let store = Arc::new(MemoryStore::default()); let view = MemoryTransactionView::new(store); let key = vec![0xA, 0xB, 0xC]; - view.put(key.clone(), 0, vec![1, 2, 3]).unwrap(); + view.put(&key, Column::Metadata, vec![1, 2, 3]).unwrap(); // test - let ret = view.delete(&key, 0).unwrap(); - let get = view.get(&key, 0).unwrap(); + let ret = view.delete(&key, Column::Metadata).unwrap(); + let get = view.get(&key, Column::Metadata).unwrap(); // verify assert_eq!(ret, Some(vec![1, 2, 3])); assert_eq!(get, None) @@ -280,11 +279,11 @@ mod tests { // setup let store = Arc::new(MemoryStore::default()); let key = vec![0xA, 0xB, 0xC]; - store.put(key.clone(), 0, vec![1, 2, 3]).unwrap(); + store.put(&key, Column::Metadata, vec![1, 2, 3]).unwrap(); let view = MemoryTransactionView::new(store); // test - let ret = view.delete(&key, 0).unwrap(); - let get = view.get(&key, 0).unwrap(); + let ret = view.delete(&key, Column::Metadata).unwrap(); + let get = view.get(&key, Column::Metadata).unwrap(); // verify assert_eq!(ret, Some(vec![1, 2, 3])); assert_eq!(get, None) @@ -295,12 +294,12 @@ mod tests { // setup let store = Arc::new(MemoryStore::default()); let key = vec![0xA, 0xB, 0xC]; - store.put(key.clone(), 0, vec![1, 2, 3]).unwrap(); + store.put(&key, Column::Metadata, vec![1, 2, 3]).unwrap(); let view = MemoryTransactionView::new(store); // test - let ret1 = view.delete(&key, 0).unwrap(); - let ret2 = view.delete(&key, 0).unwrap(); - let get = view.get(&key, 0).unwrap(); + let ret1 = view.delete(&key, Column::Metadata).unwrap(); + let ret2 = view.delete(&key, Column::Metadata).unwrap(); + let get = view.get(&key, Column::Metadata).unwrap(); // verify assert_eq!(ret1, Some(vec![1, 2, 3])); assert_eq!(ret2, None); @@ -313,9 +312,9 @@ mod tests { let store = Arc::new(MemoryStore::default()); let view = MemoryTransactionView::new(store); let key = vec![0xA, 0xB, 0xC]; - view.put(key.clone(), 0, vec![1, 2, 3]).unwrap(); + view.put(&key, Column::Metadata, vec![1, 2, 3]).unwrap(); // test - let ret = view.exists(&key, 0).unwrap(); + let ret = view.exists(&key, Column::Metadata).unwrap(); // verify assert!(ret) } @@ -325,10 +324,10 @@ mod tests { // setup let store = Arc::new(MemoryStore::default()); let key = vec![0xA, 0xB, 0xC]; - store.put(key.clone(), 0, vec![1, 2, 3]).unwrap(); + store.put(&key, Column::Metadata, vec![1, 2, 3]).unwrap(); let view = MemoryTransactionView::new(store); // test - let ret = view.exists(&key, 0).unwrap(); + let ret = view.exists(&key, Column::Metadata).unwrap(); // verify assert!(ret) } @@ -338,12 +337,12 @@ mod tests { // setup let store = Arc::new(MemoryStore::default()); let key = vec![0xA, 0xB, 0xC]; - store.put(key.clone(), 0, vec![1, 2, 3]).unwrap(); + store.put(&key, Column::Metadata, vec![1, 2, 3]).unwrap(); let view = MemoryTransactionView::new(store.clone()); - view.delete(&key, 0).unwrap(); + view.delete(&key, Column::Metadata).unwrap(); // test - let ret = view.exists(&key, 0).unwrap(); - let original = store.exists(&key, 0).unwrap(); + let ret = view.exists(&key, Column::Metadata).unwrap(); + let original = store.exists(&key, Column::Metadata).unwrap(); // verify assert!(!ret); // also ensure the original value is still intact and we aren't just passing @@ -357,10 +356,10 @@ mod tests { let store = Arc::new(MemoryStore::default()); let view = MemoryTransactionView::new(store.clone()); let key = vec![0xA, 0xB, 0xC]; - view.put(key.clone(), 0, vec![1, 2, 3]).unwrap(); + view.put(&key, Column::Metadata, vec![1, 2, 3]).unwrap(); // test view.commit().unwrap(); - let ret = store.get(&key, 0).unwrap(); + let ret = store.get(&key, Column::Metadata).unwrap(); // verify assert_eq!(ret, Some(vec![1, 2, 3])) } @@ -370,12 +369,12 @@ mod tests { // setup let store = Arc::new(MemoryStore::default()); let key = vec![0xA, 0xB, 0xC]; - store.put(key.clone(), 0, vec![1, 2, 3]).unwrap(); + store.put(&key, Column::Metadata, vec![1, 2, 3]).unwrap(); let view = MemoryTransactionView::new(store.clone()); // test - view.delete(&key, 0).unwrap(); + view.delete(&key, Column::Metadata).unwrap(); view.commit().unwrap(); - let ret = store.get(&key, 0).unwrap(); + let ret = store.get(&key, Column::Metadata).unwrap(); // verify assert_eq!(ret, None) } @@ -387,12 +386,15 @@ mod tests { let key = vec![0xA, 0xB, 0xC]; store .transaction(|store| { - store.put(key.clone(), 0, vec![1, 2, 3]).unwrap(); + store.put(&key, Column::Metadata, vec![1, 2, 3]).unwrap(); Ok(()) }) .unwrap(); - assert_eq!(store.get(&key, 0).unwrap().unwrap(), vec![1, 2, 3]); + assert_eq!( + store.get(&key, Column::Metadata).unwrap().unwrap(), + vec![1, 2, 3] + ); } #[test] @@ -400,11 +402,13 @@ mod tests { let mut store = Arc::new(MemoryStore::default()); let _ = store.transaction(|store| { - store.put(vec![0xA, 0xB, 0xC], 0, vec![1, 2, 3]).unwrap(); + store + .put(&[0xA, 0xB, 0xC], Column::Metadata, vec![1, 2, 3]) + .unwrap(); TransactionResult::<()>::Err(TransactionError::Aborted) }); - assert_eq!(store.get(&[0xA, 0xB, 0xC], 0).unwrap(), None); + assert_eq!(store.get(&[0xA, 0xB, 0xC], Column::Metadata).unwrap(), None); } #[test] @@ -412,17 +416,17 @@ mod tests { // setup let store = Arc::new(MemoryStore::default()); (0..10).step_by(2).for_each(|i| { - store.put(vec![i], 0, vec![1]).unwrap(); + store.put(&[i], Column::Metadata, vec![1]).unwrap(); }); let view = MemoryTransactionView::new(store); // test (0..10).step_by(3).for_each(|i| { - view.put(vec![i], 0, vec![2]).unwrap(); + view.put(&[i], Column::Metadata, vec![2]).unwrap(); }); let ret: Vec<_> = view - .iter_all(0, None, None, IterDirection::Forward) + .iter_all(Column::Metadata, None, None, IterDirection::Forward) .map_ok(|(k, _)| k[0]) .try_collect() .unwrap(); @@ -435,17 +439,17 @@ mod tests { // setup let store = Arc::new(MemoryStore::default()); (0..10).step_by(2).for_each(|i| { - store.put(vec![i], 0, vec![1]).unwrap(); + store.put(&[i], Column::Metadata, vec![1]).unwrap(); }); let view = MemoryTransactionView::new(store); // test (0..10).step_by(3).for_each(|i| { - view.put(vec![i], 0, vec![2]).unwrap(); + view.put(&[i], Column::Metadata, vec![2]).unwrap(); }); let ret: Vec<_> = view - .iter_all(0, None, None, IterDirection::Reverse) + .iter_all(Column::Metadata, None, None, IterDirection::Reverse) .map_ok(|(k, _)| k[0]) .try_collect() .unwrap(); @@ -458,17 +462,17 @@ mod tests { // setup let store = Arc::new(MemoryStore::default()); (0..10).step_by(2).for_each(|i| { - store.put(vec![i], 0, vec![0xA]).unwrap(); + store.put(&[i], Column::Metadata, vec![0xA]).unwrap(); }); let view = MemoryTransactionView::new(store); // test (0..10).step_by(2).for_each(|i| { - view.put(vec![i], 0, vec![0xB]).unwrap(); + view.put(&[i], Column::Metadata, vec![0xB]).unwrap(); }); let ret: Vec<_> = view - .iter_all(0, None, None, IterDirection::Forward) + .iter_all(Column::Metadata, None, None, IterDirection::Forward) // return all the values from the iterator .map_ok(|(_, v)| v[0]) .try_collect() @@ -482,16 +486,16 @@ mod tests { // setup let store = Arc::new(MemoryStore::default()); (0..10).step_by(2).for_each(|i| { - store.put(vec![i], 0, vec![0xA]).unwrap(); + store.put(&[i], Column::Metadata, vec![0xA]).unwrap(); }); let view = MemoryTransactionView::new(store); // test - let _ = view.delete(&[0], 0).unwrap(); - let _ = view.delete(&[6], 0).unwrap(); + let _ = view.delete(&[0], Column::Metadata).unwrap(); + let _ = view.delete(&[6], Column::Metadata).unwrap(); let ret: Vec<_> = view - .iter_all(0, None, None, IterDirection::Forward) + .iter_all(Column::Metadata, None, None, IterDirection::Forward) // return all the values from the iterator .map_ok(|(k, _)| k[0]) .try_collect() diff --git a/fuel-core/src/state/rocks_db.rs b/fuel-core/src/state/rocks_db.rs index e9e63a87643..50e070cf451 100644 --- a/fuel-core/src/state/rocks_db.rs +++ b/fuel-core/src/state/rocks_db.rs @@ -1,15 +1,15 @@ +#[cfg(feature = "prometheus")] +use crate::service::metrics::prometheus_metrics::DATABASE_METRICS; use crate::{ database::{ - columns, - columns::METADATA, metadata::{ DB_VERSION, DB_VERSION_KEY, }, + Column, }, state::{ BatchOperations, - ColumnId, Error, IterDirection, KVItem, @@ -18,8 +18,6 @@ use crate::{ WriteOperation, }, }; -#[cfg(feature = "metrics")] -use fuel_metrics::core_metrics::DATABASE_METRICS; use rocksdb::{ BoundColumnFamily, ColumnFamilyDescriptor, @@ -45,8 +43,14 @@ pub struct RocksDb { } impl RocksDb { - pub fn open>(path: P, cols: u32) -> Result { - let cf_descriptors: Vec<_> = (0..cols) + pub fn default_open>(path: P) -> Result { + Self::open(path, enum_iterator::all::().collect::>()) + } + + pub fn open>(path: P, columns: Vec) -> Result { + let cf_descriptors: Vec<_> = columns + .clone() + .into_iter() .map(|i| ColumnFamilyDescriptor::new(RocksDb::col_name(i), Self::cf_opts(i))) .collect(); @@ -58,7 +62,7 @@ impl RocksDb { // setup cfs match DB::open_cf(&opts, &path, &[] as &[&str]) { Ok(db) => { - for i in 0..cols { + for i in columns { db.create_cf(RocksDb::col_name(i), &opts) .map_err(|e| Error::DatabaseError(Box::new(e)))?; } @@ -76,12 +80,12 @@ impl RocksDb { } fn validate_or_set_db_version(&self) -> Result<(), Error> { - let data = self.get(DB_VERSION_KEY, METADATA)?; + let data = self.get(DB_VERSION_KEY, Column::Metadata)?; match data { None => { self.put( - DB_VERSION_KEY.to_vec(), - METADATA, + DB_VERSION_KEY, + Column::Metadata, DB_VERSION.to_be_bytes().to_vec(), )?; } @@ -97,42 +101,41 @@ impl RocksDb { Ok(()) } - fn cf(&self, column: ColumnId) -> Arc { + fn cf(&self, column: Column) -> Arc { self.db .cf_handle(&*RocksDb::col_name(column)) .expect("invalid column state") } - fn col_name(column: ColumnId) -> String { - format!("column-{}", column) + fn col_name(column: Column) -> String { + format!("column-{}", column as u32) } - fn cf_opts(column: ColumnId) -> Options { + fn cf_opts(column: Column) -> Options { let mut opts = Options::default(); opts.create_if_missing(true); - if column == columns::OWNED_COINS { - // prefix is address length - opts.set_prefix_extractor(SliceTransform::create_fixed_prefix(32)) - } - if column == columns::TRANSACTIONS_BY_OWNER_BLOCK_IDX { - // prefix is address length - opts.set_prefix_extractor(SliceTransform::create_fixed_prefix(32)) - } + match column { + Column::OwnedCoins | Column::TransactionsByOwnerBlockIdx => { + // prefix is address length + opts.set_prefix_extractor(SliceTransform::create_fixed_prefix(32)) + } + _ => {} + }; opts } } impl KeyValueStore for RocksDb { - fn get(&self, key: &[u8], column: ColumnId) -> crate::state::Result>> { - #[cfg(feature = "metrics")] + fn get(&self, key: &[u8], column: Column) -> crate::state::Result>> { + #[cfg(feature = "prometheus")] DATABASE_METRICS.read_meter.inc(); let value = self .db .get_cf(&self.cf(column), key) .map_err(|e| Error::DatabaseError(Box::new(e))); - #[cfg(feature = "metrics")] + #[cfg(feature = "prometheus")] { if value.is_ok() && value.as_ref().unwrap().is_some() { let value_as_vec = value.as_ref().cloned().unwrap().unwrap(); @@ -146,18 +149,18 @@ impl KeyValueStore for RocksDb { fn put( &self, - key: Vec, - column: ColumnId, + key: &[u8], + column: Column, value: Vec, ) -> crate::state::Result>> { - #[cfg(feature = "metrics")] + #[cfg(feature = "prometheus")] { DATABASE_METRICS.write_meter.inc(); DATABASE_METRICS .bytes_written_meter .inc_by(value.len() as u64); } - let prev = self.get(&key, column)?; + let prev = self.get(key, column)?; self.db .put_cf(&self.cf(column), key, value) .map_err(|e| Error::DatabaseError(Box::new(e))) @@ -167,7 +170,7 @@ impl KeyValueStore for RocksDb { fn delete( &self, key: &[u8], - column: ColumnId, + column: Column, ) -> crate::state::Result>> { let prev = self.get(key, column)?; self.db @@ -176,7 +179,7 @@ impl KeyValueStore for RocksDb { .map(|_| prev) } - fn exists(&self, key: &[u8], column: ColumnId) -> crate::state::Result { + fn exists(&self, key: &[u8], column: Column) -> crate::state::Result { // use pinnable mem ref to avoid memcpy of values associated with the key // since we're just checking for the existence of the key self.db @@ -187,7 +190,7 @@ impl KeyValueStore for RocksDb { fn iter_all( &self, - column: ColumnId, + column: Column, prefix: Option>, start: Option>, direction: IterDirection, @@ -223,7 +226,7 @@ impl KeyValueStore for RocksDb { item.map(|(key, value)| { let value_as_vec = value.to_vec(); let key_as_vec = key.to_vec(); - #[cfg(feature = "metrics")] + #[cfg(feature = "prometheus")] { DATABASE_METRICS.read_meter.inc(); DATABASE_METRICS @@ -268,7 +271,7 @@ impl BatchOperations for RocksDb { } } } - #[cfg(feature = "metrics")] + #[cfg(feature = "prometheus")] { DATABASE_METRICS.write_meter.inc(); DATABASE_METRICS @@ -297,28 +300,31 @@ mod tests { use super::*; use tempfile::TempDir; - fn create_db(cols: u32) -> (RocksDb, TempDir) { + fn create_db() -> (RocksDb, TempDir) { let tmp_dir = TempDir::new().unwrap(); - (RocksDb::open(tmp_dir.path(), cols).unwrap(), tmp_dir) + (RocksDb::default_open(tmp_dir.path()).unwrap(), tmp_dir) } #[test] fn can_put_and_read() { let key = vec![0xA, 0xB, 0xC]; - let (db, _tmp) = create_db(1); - db.put(key.clone(), 0, vec![1, 2, 3]).unwrap(); + let (db, _tmp) = create_db(); + db.put(&key, Column::Metadata, vec![1, 2, 3]).unwrap(); - assert_eq!(db.get(&key, 0).unwrap().unwrap(), vec![1, 2, 3]) + assert_eq!( + db.get(&key, Column::Metadata).unwrap().unwrap(), + vec![1, 2, 3] + ) } #[test] fn put_returns_previous_value() { let key = vec![0xA, 0xB, 0xC]; - let (db, _tmp) = create_db(1); - db.put(key.clone(), 0, vec![1, 2, 3]).unwrap(); - let prev = db.put(key, 0, vec![2, 4, 6]).unwrap(); + let (db, _tmp) = create_db(); + db.put(&key, Column::Metadata, vec![1, 2, 3]).unwrap(); + let prev = db.put(&key, Column::Metadata, vec![2, 4, 6]).unwrap(); assert_eq!(prev, Some(vec![1, 2, 3])); } @@ -327,21 +333,24 @@ mod tests { fn delete_and_get() { let key = vec![0xA, 0xB, 0xC]; - let (db, _tmp) = create_db(1); - db.put(key.clone(), 0, vec![1, 2, 3]).unwrap(); - assert_eq!(db.get(&key, 0).unwrap().unwrap(), vec![1, 2, 3]); + let (db, _tmp) = create_db(); + db.put(&key, Column::Metadata, vec![1, 2, 3]).unwrap(); + assert_eq!( + db.get(&key, Column::Metadata).unwrap().unwrap(), + vec![1, 2, 3] + ); - db.delete(&key, 0).unwrap(); - assert_eq!(db.get(&key, 0).unwrap(), None); + db.delete(&key, Column::Metadata).unwrap(); + assert_eq!(db.get(&key, Column::Metadata).unwrap(), None); } #[test] fn key_exists() { let key = vec![0xA, 0xB, 0xC]; - let (db, _tmp) = create_db(1); - db.put(key.clone(), 0, vec![1, 2, 3]).unwrap(); - assert!(db.exists(&key, 0).unwrap()); + let (db, _tmp) = create_db(); + db.put(&key, Column::Metadata, vec![1, 2, 3]).unwrap(); + assert!(db.exists(&key, Column::Metadata).unwrap()); } #[test] @@ -349,11 +358,15 @@ mod tests { let key = vec![0xA, 0xB, 0xC]; let value = vec![1, 2, 3]; - let (db, _tmp) = create_db(1); - let ops = vec![WriteOperation::Insert(key.clone(), 0, value.clone())]; + let (db, _tmp) = create_db(); + let ops = vec![WriteOperation::Insert( + key.clone(), + Column::Metadata, + value.clone(), + )]; db.batch_write(&mut ops.into_iter()).unwrap(); - assert_eq!(db.get(&key, 0).unwrap().unwrap(), value) + assert_eq!(db.get(&key, Column::Metadata).unwrap().unwrap(), value) } #[test] @@ -361,12 +374,12 @@ mod tests { let key = vec![0xA, 0xB, 0xC]; let value = vec![1, 2, 3]; - let (db, _tmp) = create_db(1); - db.put(key.clone(), 0, value).unwrap(); + let (db, _tmp) = create_db(); + db.put(&key, Column::Metadata, value).unwrap(); - let ops = vec![WriteOperation::Remove(key.clone(), 0)]; + let ops = vec![WriteOperation::Remove(key.clone(), Column::Metadata)]; db.batch_write(&mut ops.into_iter()).unwrap(); - assert_eq!(db.get(&key, 0).unwrap(), None); + assert_eq!(db.get(&key, Column::Metadata).unwrap(), None); } } diff --git a/fuel-core/src/test_utils.rs b/fuel-core/src/test_utils.rs index 248d601c783..fb689959e10 100644 --- a/fuel-core/src/test_utils.rs +++ b/fuel-core/src/test_utils.rs @@ -5,15 +5,18 @@ use crate::{ CoinStatus, }, }; -use fuel_core_interfaces::common::{ - fuel_asm::Word, - fuel_storage::Storage, - fuel_tx::{ - Address, - AssetId, - Bytes32, - UtxoId, +use fuel_core_interfaces::{ + common::{ + fuel_asm::Word, + fuel_storage::StorageAsMut, + fuel_tx::{ + Address, + AssetId, + Bytes32, + UtxoId, + }, }, + db::Coins, }; use itertools::Itertools; @@ -43,19 +46,19 @@ impl TestDatabase { block_created: Default::default(), }; - Storage::::insert(&mut self.database, &id, &coin).unwrap(); + self.database.storage::().insert(&id, &coin).unwrap(); (id, coin) } pub fn owned_coins(&self, owner: Address) -> Vec<(UtxoId, Coin)> { + use fuel_core_interfaces::common::fuel_storage::StorageAsRef; self.database .owned_coins(owner, None, None) .map(|res| { res.map(|id| { - let coin = Storage::::get(&self.database, &id) - .unwrap() - .unwrap(); + let coin = + self.database.storage::().get(&id).unwrap().unwrap(); (id, coin.into_owned()) }) }) diff --git a/fuel-relayer/src/mock_db.rs b/fuel-relayer/src/mock_db.rs index ce1c1c2c1b8..ac51401142e 100644 --- a/fuel-relayer/src/mock_db.rs +++ b/fuel-relayer/src/mock_db.rs @@ -14,13 +14,22 @@ use std::{ use fuel_core_interfaces::{ common::{ - fuel_storage::Storage, + fuel_storage::{ + StorageInspect, + StorageMutate, + }, fuel_tx::{ Address, MessageId, }, }, - db::KvStoreError, + db::{ + DelegatesIndexes, + KvStoreError, + Messages, + StackingDiffs, + ValidatorsSet, + }, model::{ BlockHeight, ConsensusId, @@ -65,9 +74,27 @@ impl MockDb { } } -impl Storage for MockDb { +// TODO: Generate `Storage` implementation with macro. + +impl StorageInspect for MockDb { type Error = KvStoreError; + fn get(&self, key: &MessageId) -> Result>, Self::Error> { + Ok(self + .data + .lock() + .unwrap() + .messages + .get(key) + .map(|i| Cow::Owned(i.clone()))) + } + + fn contains_key(&self, key: &MessageId) -> Result { + Ok(self.data.lock().unwrap().messages.contains_key(key)) + } +} + +impl StorageMutate for MockDb { fn insert( &mut self, key: &MessageId, @@ -84,25 +111,30 @@ impl Storage for MockDb { fn remove(&mut self, key: &MessageId) -> Result, Self::Error> { Ok(self.data.lock().unwrap().messages.remove(key)) } +} - fn get(&self, key: &MessageId) -> Result>, Self::Error> { +impl StorageInspect for MockDb { + type Error = KvStoreError; + + fn get( + &self, + key: &ValidatorId, + ) -> Result)>>, Self::Error> { Ok(self .data .lock() .unwrap() - .messages + .validators .get(key) - .map(|i| Cow::Owned(i.clone()))) + .map(|i| Cow::Owned(*i))) } - fn contains_key(&self, key: &MessageId) -> Result { - Ok(self.data.lock().unwrap().messages.contains_key(key)) + fn contains_key(&self, key: &ValidatorId) -> Result { + Ok(self.data.lock().unwrap().validators.contains_key(key)) } } -impl Storage)> for MockDb { - type Error = KvStoreError; - +impl StorageMutate for MockDb { fn insert( &mut self, key: &ValidatorId, @@ -117,39 +149,38 @@ impl Storage)> for MockDb { ) -> Result)>, Self::Error> { Ok(self.data.lock().unwrap().validators.remove(key)) } +} - fn get( - &self, - key: &ValidatorId, - ) -> Result)>>, Self::Error> { +impl StorageInspect for MockDb { + type Error = KvStoreError; + + fn get(&self, key: &Address) -> Result>>, Self::Error> { Ok(self .data .lock() .unwrap() - .validators + .delegator_index .get(key) - .map(|i| Cow::Owned(*i))) + .map(|i| Cow::Owned(i.clone()))) } - fn contains_key(&self, key: &ValidatorId) -> Result { - Ok(self.data.lock().unwrap().validators.contains_key(key)) + fn contains_key(&self, key: &Address) -> Result { + Ok(self.data.lock().unwrap().delegator_index.contains_key(key)) } } -impl Storage> for MockDb { - type Error = KvStoreError; - +impl StorageMutate for MockDb { fn insert( &mut self, key: &Address, - value: &Vec, + value: &[DaBlockHeight], ) -> Result>, Self::Error> { Ok(self .data .lock() .unwrap() .delegator_index - .insert(*key, value.clone())) + .insert(*key, value.into())) } fn remove( @@ -158,25 +189,27 @@ impl Storage> for MockDb { ) -> Result>, Self::Error> { Ok(self.data.lock().unwrap().delegator_index.remove(key)) } +} - fn get(&self, key: &Address) -> Result>>, Self::Error> { +impl StorageInspect for MockDb { + type Error = KvStoreError; + + fn get(&self, key: &DaBlockHeight) -> Result>, Self::Error> { Ok(self .data .lock() .unwrap() - .delegator_index + .staking_diffs .get(key) .map(|i| Cow::Owned(i.clone()))) } - fn contains_key(&self, key: &Address) -> Result { - Ok(self.data.lock().unwrap().delegator_index.contains_key(key)) + fn contains_key(&self, key: &DaBlockHeight) -> Result { + Ok(self.data.lock().unwrap().staking_diffs.contains_key(key)) } } -impl Storage for MockDb { - type Error = KvStoreError; - +impl StorageMutate for MockDb { fn insert( &mut self, key: &DaBlockHeight, @@ -196,20 +229,6 @@ impl Storage for MockDb { ) -> Result, Self::Error> { Ok(self.data.lock().unwrap().staking_diffs.remove(key)) } - - fn get(&self, key: &DaBlockHeight) -> Result>, Self::Error> { - Ok(self - .data - .lock() - .unwrap() - .staking_diffs - .get(key) - .map(|i| Cow::Owned(i.clone()))) - } - - fn contains_key(&self, key: &DaBlockHeight) -> Result { - Ok(self.data.lock().unwrap().staking_diffs.contains_key(key)) - } } #[async_trait] diff --git a/fuel-tests/tests/blocks.rs b/fuel-tests/tests/blocks.rs index f82ba03c629..4ce2bbfa113 100644 --- a/fuel-tests/tests/blocks.rs +++ b/fuel-tests/tests/blocks.rs @@ -3,7 +3,10 @@ use chrono::{ Utc, }; use fuel_core::{ - database::Database, + database::{ + storage::FuelBlocks, + Database, + }, model::{ FuelBlockDb, FuelBlockHeader, @@ -15,9 +18,8 @@ use fuel_core::{ }, }; use fuel_core_interfaces::common::{ - fuel_storage::Storage, + fuel_storage::StorageAsMut, fuel_tx, - fuel_types, }; use fuel_gql_client::client::{ types::TransactionStatus, @@ -36,7 +38,7 @@ async fn block() { let block = FuelBlockDb::default(); let id = block.id(); let mut db = Database::default(); - Storage::::insert(&mut db, &id, &block).unwrap(); + db.storage::().insert(&id, &block).unwrap(); // setup server & client let srv = FuelService::from_database(db, Config::local_node()) @@ -157,8 +159,7 @@ async fn block_connection_first_5() { let mut db = Database::default(); for block in blocks { let id = block.id(); - Storage::::insert(&mut db, &id, &block) - .unwrap(); + db.storage::().insert(&id, &block).unwrap(); } // setup server & client @@ -203,8 +204,7 @@ async fn block_connection_last_5() { let mut db = Database::default(); for block in blocks { let id = block.id(); - Storage::::insert(&mut db, &id, &block) - .unwrap(); + db.storage::().insert(&id, &block).unwrap(); } // setup server & client diff --git a/fuel-tests/tests/coin.rs b/fuel-tests/tests/coin.rs index d5b7d2a6511..7e7eb8af7c9 100644 --- a/fuel-tests/tests/coin.rs +++ b/fuel-tests/tests/coin.rs @@ -13,17 +13,20 @@ use fuel_core::{ FuelService, }, }; -use fuel_core_interfaces::common::{ - fuel_storage::Storage, - fuel_tx::{ - AssetId, - UtxoId, - }, - fuel_vm::prelude::{ - Address, - Bytes32, - Word, +use fuel_core_interfaces::{ + common::{ + fuel_storage::StorageAsMut, + fuel_tx::{ + AssetId, + UtxoId, + }, + fuel_vm::prelude::{ + Address, + Bytes32, + Word, + }, }, + db::Coins, }; use fuel_gql_client::client::{ schema::coin::CoinStatus as SchemeCoinStatus, @@ -47,7 +50,7 @@ async fn coin() { let utxo_id = UtxoId::new(Default::default(), 5); let mut db = Database::default(); - Storage::::insert(&mut db, &utxo_id, &coin).unwrap(); + db.storage::().insert(&utxo_id, &coin).unwrap(); // setup server & client let srv = FuelService::from_database(db, Config::local_node()) .await @@ -85,7 +88,7 @@ async fn first_5_coins() { let mut db = Database::default(); for (utxo_id, coin) in coins { - Storage::::insert(&mut db, &utxo_id, &coin).unwrap(); + db.storage::().insert(&utxo_id, &coin).unwrap(); } // setup server & client @@ -135,7 +138,7 @@ async fn only_asset_id_filtered_coins() { let mut db = Database::default(); for (id, coin) in coins { - Storage::::insert(&mut db, &id, &coin).unwrap(); + db.storage::().insert(&id, &coin).unwrap(); } // setup server & client @@ -192,7 +195,7 @@ async fn only_unspent_coins() { let mut db = Database::default(); for (id, coin) in coins { - Storage::::insert(&mut db, &id, &coin).unwrap(); + db.storage::().insert(&id, &coin).unwrap(); } // setup server & client diff --git a/fuel-txpool/src/containers/dependency.rs b/fuel-txpool/src/containers/dependency.rs index 9593383833f..6f756e28d06 100644 --- a/fuel-txpool/src/containers/dependency.rs +++ b/fuel-txpool/src/containers/dependency.rs @@ -403,7 +403,7 @@ impl Dependency { // verify message id integrity Self::check_if_message_input_matches_id(input)?; // since message id is derived, we don't need to double check all the fields - if let Some(msg) = db.message(*message_id)? { + if let Some(msg) = db.message(message_id)? { // return an error if spent block is set if msg.fuel_block_spend.is_some() { return Err( @@ -452,7 +452,7 @@ impl Dependency { return Err(Error::NotInsertedMaxDepth.into()) } } else { - if !db.contract_exist(*contract_id)? { + if !db.contract_exist(contract_id)? { return Err(Error::NotInsertedInputContractNotExisting( *contract_id, ) diff --git a/fuel-txpool/src/mock_db.rs b/fuel-txpool/src/mock_db.rs index 8fb538b60dd..849e7483dc5 100644 --- a/fuel-txpool/src/mock_db.rs +++ b/fuel-txpool/src/mock_db.rs @@ -9,7 +9,10 @@ use std::{ use fuel_core_interfaces::{ common::{ - fuel_storage::Storage, + fuel_storage::{ + StorageInspect, + StorageMutate, + }, fuel_tx::{ Contract, ContractId, @@ -18,8 +21,11 @@ use fuel_core_interfaces::{ }, }, db::{ + Coins, + ContractsRawCode, Error, KvStoreError, + Messages, }, model::{ Coin, @@ -40,9 +46,27 @@ pub(crate) struct MockDb { pub data: Arc>, } -impl Storage for MockDb { +// TODO: Generate storage implementation with macro. + +impl StorageInspect for MockDb { type Error = KvStoreError; + fn get(&self, key: &UtxoId) -> Result>, Self::Error> { + Ok(self + .data + .lock() + .unwrap() + .coins + .get(key) + .map(|i| Cow::Owned(i.clone()))) + } + + fn contains_key(&self, key: &UtxoId) -> Result { + Ok(self.data.lock().unwrap().coins.contains_key(key)) + } +} + +impl StorageMutate for MockDb { fn insert( &mut self, key: &UtxoId, @@ -54,60 +78,64 @@ impl Storage for MockDb { fn remove(&mut self, key: &UtxoId) -> Result, Self::Error> { Ok(self.data.lock().unwrap().coins.remove(key)) } +} - fn get(&self, key: &UtxoId) -> Result>, Self::Error> { +impl StorageInspect for MockDb { + type Error = Error; + + fn get(&self, key: &ContractId) -> Result>, Self::Error> { Ok(self .data .lock() .unwrap() - .coins + .contracts .get(key) .map(|i| Cow::Owned(i.clone()))) } - fn contains_key(&self, key: &UtxoId) -> Result { - Ok(self.data.lock().unwrap().coins.contains_key(key)) + fn contains_key(&self, key: &ContractId) -> Result { + Ok(self.data.lock().unwrap().contracts.contains_key(key)) } } -impl Storage for MockDb { - type Error = Error; - +impl StorageMutate for MockDb { fn insert( &mut self, key: &ContractId, - value: &Contract, + value: &[u8], ) -> Result, Self::Error> { Ok(self .data .lock() .unwrap() .contracts - .insert(*key, value.clone())) + .insert(*key, value.into())) } fn remove(&mut self, key: &ContractId) -> Result, Self::Error> { Ok(self.data.lock().unwrap().contracts.remove(key)) } +} - fn get(&self, key: &ContractId) -> Result>, Self::Error> { +impl StorageInspect for MockDb { + type Error = KvStoreError; + + fn get(&self, key: &MessageId) -> Result>, Self::Error> { Ok(self .data .lock() .unwrap() - .contracts + .messages .get(key) .map(|i| Cow::Owned(i.clone()))) } - fn contains_key(&self, key: &ContractId) -> Result { - Ok(self.data.lock().unwrap().contracts.contains_key(key)) + fn contains_key(&self, key: &MessageId) -> Result { + Ok(self.data.lock().unwrap().messages.contains_key(key)) } } -impl Storage for MockDb { - type Error = KvStoreError; - +impl StorageMutate for MockDb { fn insert( &mut self, key: &MessageId, @@ -124,20 +152,6 @@ impl Storage for MockDb { fn remove(&mut self, key: &MessageId) -> Result, Self::Error> { Ok(self.data.lock().unwrap().messages.remove(key)) } - - fn get(&self, key: &MessageId) -> Result>, Self::Error> { - Ok(self - .data - .lock() - .unwrap() - .messages - .get(key) - .map(|i| Cow::Owned(i.clone()))) - } - - fn contains_key(&self, key: &MessageId) -> Result { - Ok(self.data.lock().unwrap().messages.contains_key(key)) - } } impl TxPoolDb for MockDb {} diff --git a/fuel-txpool/src/txpool.rs b/fuel-txpool/src/txpool.rs index 3ac70030c6a..89f410b34da 100644 --- a/fuel-txpool/src/txpool.rs +++ b/fuel-txpool/src/txpool.rs @@ -270,7 +270,42 @@ impl TxPool { #[cfg(test)] pub mod tests { - use crate::MockDb; + use super::*; + use crate::{ + txpool::tests::helpers::{ + create_coin_input, + create_coin_output, + create_contract_input, + create_contract_output, + }, + Error, + MockDb, + }; + use fuel_core_interfaces::{ + common::{ + fuel_storage::StorageAsMut, + fuel_tx::{ + TransactionBuilder, + UtxoId, + }, + }, + db::{ + Coins, + Messages, + }, + model::{ + BlockHeight, + Coin, + CoinStatus, + Message, + }, + }; + use std::{ + cmp::Reverse, + str::FromStr, + sync::Arc, + }; + mod helpers { use crate::types::TxId; use fuel_core_interfaces::{ @@ -336,37 +371,6 @@ pub mod tests { } } - use super::*; - use crate::{ - txpool::tests::helpers::{ - create_coin_input, - create_coin_output, - create_contract_input, - create_contract_output, - }, - Error, - }; - use fuel_core_interfaces::{ - common::{ - fuel_storage::Storage, - fuel_tx::{ - TransactionBuilder, - UtxoId, - }, - }, - model::{ - BlockHeight, - Coin, - CoinStatus, - Message, - }, - }; - use std::{ - cmp::Reverse, - str::FromStr, - sync::Arc, - }; - #[tokio::test] async fn simple_insertion() { let mut txpool = TxPool::new(Default::default()); @@ -419,18 +423,19 @@ pub mod tests { "0x0000000000000000000000000000000000000000000000000000000000000000", ) .unwrap(); - db.insert( - &UtxoId::new(db_tx_id, 0), - &Coin { - owner: Default::default(), - amount: Default::default(), - asset_id: Default::default(), - maturity: Default::default(), - status: CoinStatus::Unspent, - block_created: BlockHeight::default(), - }, - ) - .expect("unable to insert seed coin data"); + db.storage::() + .insert( + &UtxoId::new(db_tx_id, 0), + &Coin { + owner: Default::default(), + amount: Default::default(), + asset_id: Default::default(), + maturity: Default::default(), + status: CoinStatus::Unspent, + block_created: BlockHeight::default(), + }, + ) + .expect("unable to insert seed coin data"); let contract_id = ContractId::from_str( "0x0000000000000000000000000000000000000000000000000000000000000100", @@ -477,18 +482,19 @@ pub mod tests { "0x0000000000000000000000000000000000000000000000000000000000000000", ) .unwrap(); - db.insert( - &UtxoId::new(db_tx_id, 0), - &Coin { - owner: Default::default(), - amount: Default::default(), - asset_id: Default::default(), - maturity: Default::default(), - status: CoinStatus::Unspent, - block_created: BlockHeight::default(), - }, - ) - .expect("unable to insert seed coin data"); + db.storage::() + .insert( + &UtxoId::new(db_tx_id, 0), + &Coin { + owner: Default::default(), + amount: Default::default(), + asset_id: Default::default(), + maturity: Default::default(), + status: CoinStatus::Unspent, + block_created: BlockHeight::default(), + }, + ) + .expect("unable to insert seed coin data"); let contract_id = ContractId::from_str( "0x0000000000000000000000000000000000000000000000000000000000000100", @@ -577,18 +583,19 @@ pub mod tests { "0x0000000000000000000000000000000000000000000000000000000000000000", ) .unwrap(); - db.insert( - &UtxoId::new(db_tx_id, 0), - &Coin { - owner: Default::default(), - amount: Default::default(), - asset_id: Default::default(), - maturity: Default::default(), - status: CoinStatus::Spent, - block_created: BlockHeight::default(), - }, - ) - .expect("unable to insert seed coin data"); + db.storage::() + .insert( + &UtxoId::new(db_tx_id, 0), + &Coin { + owner: Default::default(), + amount: Default::default(), + asset_id: Default::default(), + maturity: Default::default(), + status: CoinStatus::Spent, + block_created: BlockHeight::default(), + }, + ) + .expect("unable to insert seed coin data"); let tx = Arc::new( TransactionBuilder::script(vec![], vec![]) @@ -615,18 +622,19 @@ pub mod tests { "0x0000000000000000000000000000000000000000000000000000000000000000", ) .unwrap(); - db.insert( - &UtxoId::new(db_tx_id, 0), - &Coin { - owner: Default::default(), - amount: Default::default(), - asset_id: Default::default(), - maturity: Default::default(), - status: CoinStatus::Unspent, - block_created: BlockHeight::default(), - }, - ) - .expect("unable to insert seed coin data"); + db.storage::() + .insert( + &UtxoId::new(db_tx_id, 0), + &Coin { + owner: Default::default(), + amount: Default::default(), + asset_id: Default::default(), + maturity: Default::default(), + status: CoinStatus::Unspent, + block_created: BlockHeight::default(), + }, + ) + .expect("unable to insert seed coin data"); let tx1 = Arc::new( TransactionBuilder::script(vec![], vec![]) @@ -774,18 +782,19 @@ pub mod tests { "0x0000000000000000000000000000000000000000000000000000000000000000", ) .unwrap(); - db.insert( - &UtxoId::new(db_tx_id, 0), - &Coin { - owner: Default::default(), - amount: Default::default(), - asset_id: Default::default(), - maturity: Default::default(), - status: CoinStatus::Unspent, - block_created: BlockHeight::default(), - }, - ) - .expect("unable to insert seed coin data"); + db.storage::() + .insert( + &UtxoId::new(db_tx_id, 0), + &Coin { + owner: Default::default(), + amount: Default::default(), + asset_id: Default::default(), + maturity: Default::default(), + status: CoinStatus::Unspent, + block_created: BlockHeight::default(), + }, + ) + .expect("unable to insert seed coin data"); let tx1 = Arc::new( TransactionBuilder::script(vec![], vec![]) @@ -1044,7 +1053,9 @@ pub mod tests { .finalize(); let mut db = MockDb::default(); - db.insert(&message.id(), &message).unwrap(); + db.storage::() + .insert(&message.id(), &message) + .unwrap(); let mut txpool = TxPool::new(Default::default()); txpool @@ -1070,7 +1081,9 @@ pub mod tests { .finalize(); let mut db = MockDb::default(); - db.insert(&message.id(), &message).unwrap(); + db.storage::() + .insert(&message.id(), &message) + .unwrap(); let mut txpool = TxPool::new(Default::default()); let err = txpool @@ -1135,7 +1148,9 @@ pub mod tests { .finalize(); let mut db = MockDb::default(); - db.insert(&message.id(), &message).unwrap(); + db.storage::() + .insert(&message.id(), &message) + .unwrap(); let mut txpool = TxPool::new(Default::default()); @@ -1181,7 +1196,9 @@ pub mod tests { .finalize(); let mut db = MockDb::default(); - db.insert(&message.id(), &message).unwrap(); + db.storage::() + .insert(&message.id(), &message) + .unwrap(); let mut txpool = TxPool::new(Default::default()); @@ -1246,8 +1263,12 @@ pub mod tests { .finalize(); let mut db = MockDb::default(); - db.insert(&message_1.id(), &message_1).unwrap(); - db.insert(&message_2.id(), &message_2).unwrap(); + db.storage::() + .insert(&message_1.id(), &message_1) + .unwrap(); + db.storage::() + .insert(&message_2.id(), &message_2) + .unwrap(); let mut txpool = TxPool::new(Default::default()); txpool From f102cc100c06c1eadc707c354a338d82370dc725 Mon Sep 17 00:00:00 2001 From: green Date: Fri, 9 Sep 2022 22:00:14 +0100 Subject: [PATCH 2/7] Merge with `master` --- Cargo.lock | 28 ++++------------------------ fuel-client/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d1d8d2bf200..af789208d2c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2192,7 +2192,7 @@ dependencies = [ "fuel-storage 0.3.0", "fuel-tx", "fuel-types", - "fuel-vm 0.15.0 (git+https://github.com/FuelLabs/fuel-vm?branch=feature/split-storage-trait)", + "fuel-vm", "futures", "lazy_static", "parking_lot 0.12.1", @@ -2229,7 +2229,7 @@ dependencies = [ "derive_more", "fuel-tx", "fuel-types", - "fuel-vm 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "fuel-vm", "futures", "hex", "insta", @@ -2422,29 +2422,9 @@ dependencies = [ [[package]] name = "fuel-vm" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44bdbc4b0863a4d7d523b248d404821dc4e3b6d0034fbbf33f03b1f4283af663" -dependencies = [ - "fuel-asm", - "fuel-crypto", - "fuel-merkle 0.3.0", - "fuel-storage 0.2.0", - "fuel-tx", - "fuel-types", - "itertools", - "secp256k1", - "serde", - "sha3", - "tai64", - "thiserror", - "tracing", -] - -[[package]] -name = "fuel-vm" -version = "0.15.0" -source = "git+https://github.com/FuelLabs/fuel-vm?branch=feature/split-storage-trait#06ef9eb4fd60cc5e8021a239cc478ecb608ebc36" +checksum = "6658f32707cb114d464561ed6e304e9830da6a4e74da3e5fcdab4aad94d81361" dependencies = [ "anyhow", "fuel-asm", diff --git a/fuel-client/Cargo.toml b/fuel-client/Cargo.toml index eda406fd5f8..f824361848a 100644 --- a/fuel-client/Cargo.toml +++ b/fuel-client/Cargo.toml @@ -22,7 +22,7 @@ cynic = { version = "1.0", features = ["surf"] } derive_more = { version = "0.99" } fuel-tx = { version = "0.19", features = ["serde"] } fuel-types = { version = "0.5", features = ["serde"] } -fuel-vm = { version = "0.16", features = ["serde"] } +fuel-vm = { version = "0.17", features = ["serde"] } futures = "0.3" hex = "0.4" itertools = "0.10" From 6999fb6d6bf15ace23d12da72fc22c3bdb98ae4d Mon Sep 17 00:00:00 2001 From: green Date: Fri, 9 Sep 2022 22:38:34 +0100 Subject: [PATCH 3/7] Reverted back the change of the `database` structure. --- fuel-core-interfaces/src/relayer.rs | 8 +- fuel-core/src/database.rs | 244 +++++++++++++++++- .../src/database/{storage => }/balances.rs | 0 fuel-core/src/database/{storage => }/block.rs | 0 .../src/database/{storage => }/code_root.rs | 0 fuel-core/src/database/{storage => }/coin.rs | 0 .../src/database/{storage => }/contracts.rs | 0 .../database/{storage => }/delegates_index.rs | 0 .../src/database/{storage => }/message.rs | 0 .../src/database/{storage => }/receipts.rs | 0 fuel-core/src/database/relayer.rs | 218 ---------------- .../database/{storage => }/staking_diffs.rs | 0 fuel-core/src/database/{storage => }/state.rs | 0 fuel-core/src/database/storage.rs | 13 - fuel-core/src/database/storage/transaction.rs | 140 ---------- fuel-core/src/database/transaction.rs | 138 +++++++++- .../database/{storage => }/validator_set.rs | 0 fuel-core/src/state/rocks_db.rs | 14 +- 18 files changed, 390 insertions(+), 385 deletions(-) rename fuel-core/src/database/{storage => }/balances.rs (100%) rename fuel-core/src/database/{storage => }/block.rs (100%) rename fuel-core/src/database/{storage => }/code_root.rs (100%) rename fuel-core/src/database/{storage => }/coin.rs (100%) rename fuel-core/src/database/{storage => }/contracts.rs (100%) rename fuel-core/src/database/{storage => }/delegates_index.rs (100%) rename fuel-core/src/database/{storage => }/message.rs (100%) rename fuel-core/src/database/{storage => }/receipts.rs (100%) delete mode 100644 fuel-core/src/database/relayer.rs rename fuel-core/src/database/{storage => }/staking_diffs.rs (100%) rename fuel-core/src/database/{storage => }/state.rs (100%) delete mode 100644 fuel-core/src/database/storage/transaction.rs rename fuel-core/src/database/{storage => }/validator_set.rs (100%) diff --git a/fuel-core-interfaces/src/relayer.rs b/fuel-core-interfaces/src/relayer.rs index 17b18178655..9f57f65d4e0 100644 --- a/fuel-core-interfaces/src/relayer.rs +++ b/fuel-core-interfaces/src/relayer.rs @@ -104,8 +104,8 @@ pub trait RelayerDb: delegate: &Address, da_height: DaBlockHeight, ) -> Option> { - let storage = self.storage::(); - let delegate_index = storage + let delegate_index = self + .storage::() .get(delegate) .expect("Expect to get data without problem")?; let mut last_da_height = 0; @@ -120,8 +120,8 @@ pub trait RelayerDb: return None } // get staking diff - let storage = self.storage::(); - let staking_diff = storage + let staking_diff = self + .storage::() .get(&last_da_height) .expect("Expect to get data without problem")?; diff --git a/fuel-core/src/database.rs b/fuel-core/src/database.rs index 701038558d8..f3bcb6b063d 100644 --- a/fuel-core/src/database.rs +++ b/fuel-core/src/database.rs @@ -51,8 +51,21 @@ use std::path::Path; #[cfg(feature = "rocksdb")] use tempfile::TempDir; +// Storages implementation +// TODO: Move to separate `database/storage` folder, because it is only implementation of storages traits. +mod balances; +mod block; +mod code_root; +mod coin; +mod contracts; +mod delegates_index; +mod message; +mod receipts; +mod staking_diffs; +mod state; +mod validator_set; + pub mod metadata; -mod relayer; pub mod storage; pub mod transaction; pub mod transactional; @@ -79,7 +92,7 @@ pub enum Column { TransactionsByOwnerBlockIdx = 10, Receipts = 11, Blocks = 12, - /// maps block id -> block hash + /// Maps block id to block hash BlockIds = 13, Messages = 14, /// Contain current validator stake and it consensus_key if set. @@ -308,3 +321,230 @@ impl P2pDb for Database { ::get_sealed_block(self, height).await } } + +// TODO: Move to a separate file `database/relayer.rs` +mod relayer { + use crate::database::{ + metadata, + Column, + Database, + }; + use fuel_core_interfaces::{ + common::fuel_storage::StorageAsMut, + db::ValidatorsSet, + model::{ + BlockHeight, + ConsensusId, + DaBlockHeight, + SealedFuelBlock, + ValidatorId, + ValidatorStake, + }, + relayer::{ + RelayerDb, + StakingDiff, + }, + }; + use std::{ + collections::HashMap, + ops::DerefMut, + sync::Arc, + }; + + #[async_trait::async_trait] + impl RelayerDb for Database { + async fn get_validators( + &self, + ) -> HashMap)> { + struct WrapAddress(pub ValidatorId); + impl From> for WrapAddress { + fn from(i: Vec) -> Self { + Self(ValidatorId::try_from(i.as_ref()).unwrap()) + } + } + let mut out = HashMap::new(); + for diff in self + .iter_all::)>( + Column::ValidatorSet, + None, + None, + None, + ) + { + match diff { + Ok((address, stake)) => { + out.insert(address.0, stake); + } + Err(err) => panic!("Database internal error:{:?}", err), + } + } + out + } + + async fn get_staking_diffs( + &self, + from_da_height: DaBlockHeight, + to_da_height: Option, + ) -> Vec<(DaBlockHeight, StakingDiff)> { + let to_da_height = if let Some(to_da_height) = to_da_height { + if from_da_height > to_da_height { + return Vec::new() + } + to_da_height + } else { + DaBlockHeight::MAX + }; + struct WrapU64Be(pub DaBlockHeight); + impl From> for WrapU64Be { + fn from(i: Vec) -> Self { + use byteorder::{ + BigEndian, + ReadBytesExt, + }; + use std::io::Cursor; + let mut i = Cursor::new(i); + Self(i.read_u64::().unwrap_or_default()) + } + } + let mut out = Vec::new(); + for diff in self.iter_all::( + Column::StackingDiffs, + None, + Some(from_da_height.to_be_bytes().to_vec()), + None, + ) { + match diff { + Ok((key, diff)) => { + let block = key.0; + if block > to_da_height { + return out + } + out.push((block, diff)) + } + Err(err) => panic!("get_validator_diffs unexpected error:{:?}", err), + } + } + out + } + + async fn apply_validator_diffs( + &mut self, + da_height: DaBlockHeight, + changes: &HashMap)>, + ) { + // this is reimplemented here to assure it is atomic operation in case of poweroff situation. + let mut db = self.transaction(); + // TODO + for (address, stake) in changes { + let _ = db + .deref_mut() + .storage::() + .insert(address, stake); + } + db.set_validators_da_height(da_height).await; + if let Err(err) = db.commit() { + panic!("apply_validator_diffs database corrupted: {:?}", err); + } + } + + async fn get_chain_height(&self) -> BlockHeight { + match self.get_block_height() { + Ok(res) => { + res.expect("get_block_height value should be always present and set") + } + Err(err) => { + panic!("get_block_height database corruption, err:{:?}", err); + } + } + } + + async fn get_sealed_block( + &self, + _height: BlockHeight, + ) -> Option> { + // TODO + Some(Arc::new(SealedFuelBlock::default())) + } + + async fn set_finalized_da_height(&self, block: DaBlockHeight) { + let _: Option = self + .insert(metadata::FINALIZED_DA_HEIGHT_KEY, Column::Metadata, block) + .unwrap_or_else(|err| { + panic!("set_finalized_da_height should always succeed: {:?}", err); + }); + } + + async fn get_finalized_da_height(&self) -> DaBlockHeight { + match self.get(metadata::FINALIZED_DA_HEIGHT_KEY, Column::Metadata) { + Ok(res) => { + return res.expect( + "get_finalized_da_height value should be always present and set", + ) + } + Err(err) => { + panic!("get_finalized_da_height database corruption, err:{:?}", err); + } + } + } + + async fn set_validators_da_height(&self, block: DaBlockHeight) { + let _: Option = self + .insert(metadata::VALIDATORS_DA_HEIGHT_KEY, Column::Metadata, block) + .unwrap_or_else(|err| { + panic!("set_validators_da_height should always succeed: {:?}", err); + }); + } + + async fn get_validators_da_height(&self) -> DaBlockHeight { + match self.get(metadata::VALIDATORS_DA_HEIGHT_KEY, Column::Metadata) { + Ok(res) => { + return res.expect( + "get_validators_da_height value should be always present and set", + ) + } + Err(err) => { + panic!( + "get_validators_da_height database corruption, err:{:?}", + err + ); + } + } + } + + async fn get_last_committed_finalized_fuel_height(&self) -> BlockHeight { + match self.get( + metadata::LAST_COMMITTED_FINALIZED_BLOCK_HEIGHT_KEY, + Column::Metadata, + ) { + Ok(res) => { + return res + .expect("set_last_committed_finalized_fuel_height value should be always present and set"); + } + Err(err) => { + panic!( + "set_last_committed_finalized_fuel_height database corruption, err:{:?}", + err + ); + } + } + } + + async fn set_last_committed_finalized_fuel_height( + &self, + block_height: BlockHeight, + ) { + let _: Option = self + .insert( + metadata::LAST_COMMITTED_FINALIZED_BLOCK_HEIGHT_KEY, + Column::Metadata, + block_height, + ) + .unwrap_or_else(|err| { + panic!( + "set_last_committed_finalized_fuel_height should always succeed: {:?}", + err + ); + }); + } + } +} diff --git a/fuel-core/src/database/storage/balances.rs b/fuel-core/src/database/balances.rs similarity index 100% rename from fuel-core/src/database/storage/balances.rs rename to fuel-core/src/database/balances.rs diff --git a/fuel-core/src/database/storage/block.rs b/fuel-core/src/database/block.rs similarity index 100% rename from fuel-core/src/database/storage/block.rs rename to fuel-core/src/database/block.rs diff --git a/fuel-core/src/database/storage/code_root.rs b/fuel-core/src/database/code_root.rs similarity index 100% rename from fuel-core/src/database/storage/code_root.rs rename to fuel-core/src/database/code_root.rs diff --git a/fuel-core/src/database/storage/coin.rs b/fuel-core/src/database/coin.rs similarity index 100% rename from fuel-core/src/database/storage/coin.rs rename to fuel-core/src/database/coin.rs diff --git a/fuel-core/src/database/storage/contracts.rs b/fuel-core/src/database/contracts.rs similarity index 100% rename from fuel-core/src/database/storage/contracts.rs rename to fuel-core/src/database/contracts.rs diff --git a/fuel-core/src/database/storage/delegates_index.rs b/fuel-core/src/database/delegates_index.rs similarity index 100% rename from fuel-core/src/database/storage/delegates_index.rs rename to fuel-core/src/database/delegates_index.rs diff --git a/fuel-core/src/database/storage/message.rs b/fuel-core/src/database/message.rs similarity index 100% rename from fuel-core/src/database/storage/message.rs rename to fuel-core/src/database/message.rs diff --git a/fuel-core/src/database/storage/receipts.rs b/fuel-core/src/database/receipts.rs similarity index 100% rename from fuel-core/src/database/storage/receipts.rs rename to fuel-core/src/database/receipts.rs diff --git a/fuel-core/src/database/relayer.rs b/fuel-core/src/database/relayer.rs deleted file mode 100644 index 04426cfb34c..00000000000 --- a/fuel-core/src/database/relayer.rs +++ /dev/null @@ -1,218 +0,0 @@ -use crate::database::{ - metadata, - Column, - Database, -}; -use fuel_core_interfaces::{ - common::fuel_storage::StorageAsMut, - db::ValidatorsSet, - model::{ - BlockHeight, - ConsensusId, - DaBlockHeight, - SealedFuelBlock, - ValidatorId, - ValidatorStake, - }, - relayer::{ - RelayerDb, - StakingDiff, - }, -}; -use std::{ - collections::HashMap, - ops::DerefMut, - sync::Arc, -}; - -#[async_trait::async_trait] -impl RelayerDb for Database { - async fn get_validators( - &self, - ) -> HashMap)> { - struct WrapAddress(pub ValidatorId); - impl From> for WrapAddress { - fn from(i: Vec) -> Self { - Self(ValidatorId::try_from(i.as_ref()).unwrap()) - } - } - let mut out = HashMap::new(); - for diff in self.iter_all::)>( - Column::ValidatorSet, - None, - None, - None, - ) { - match diff { - Ok((address, stake)) => { - out.insert(address.0, stake); - } - Err(err) => panic!("Database internal error:{:?}", err), - } - } - out - } - - async fn get_staking_diffs( - &self, - from_da_height: DaBlockHeight, - to_da_height: Option, - ) -> Vec<(DaBlockHeight, StakingDiff)> { - let to_da_height = if let Some(to_da_height) = to_da_height { - if from_da_height > to_da_height { - return Vec::new() - } - to_da_height - } else { - DaBlockHeight::MAX - }; - struct WrapU64Be(pub DaBlockHeight); - impl From> for WrapU64Be { - fn from(i: Vec) -> Self { - use byteorder::{ - BigEndian, - ReadBytesExt, - }; - use std::io::Cursor; - let mut i = Cursor::new(i); - Self(i.read_u64::().unwrap_or_default()) - } - } - let mut out = Vec::new(); - for diff in self.iter_all::( - Column::StackingDiffs, - None, - Some(from_da_height.to_be_bytes().to_vec()), - None, - ) { - match diff { - Ok((key, diff)) => { - let block = key.0; - if block > to_da_height { - return out - } - out.push((block, diff)) - } - Err(err) => panic!("get_validator_diffs unexpected error:{:?}", err), - } - } - out - } - - async fn apply_validator_diffs( - &mut self, - da_height: DaBlockHeight, - changes: &HashMap)>, - ) { - // this is reimplemented here to assure it is atomic operation in case of poweroff situation. - let mut db = self.transaction(); - // TODO - for (address, stake) in changes { - let _ = db - .deref_mut() - .storage::() - .insert(address, stake); - } - db.set_validators_da_height(da_height).await; - if let Err(err) = db.commit() { - panic!("apply_validator_diffs database corrupted: {:?}", err); - } - } - - async fn get_chain_height(&self) -> BlockHeight { - match self.get_block_height() { - Ok(res) => { - res.expect("get_block_height value should be always present and set") - } - Err(err) => { - panic!("get_block_height database corruption, err:{:?}", err); - } - } - } - - async fn get_sealed_block( - &self, - _height: BlockHeight, - ) -> Option> { - // TODO - Some(Arc::new(SealedFuelBlock::default())) - } - - async fn set_finalized_da_height(&self, block: DaBlockHeight) { - let _: Option = self - .insert(metadata::FINALIZED_DA_HEIGHT_KEY, Column::Metadata, block) - .unwrap_or_else(|err| { - panic!("set_finalized_da_height should always succeed: {:?}", err); - }); - } - - async fn get_finalized_da_height(&self) -> DaBlockHeight { - match self.get(metadata::FINALIZED_DA_HEIGHT_KEY, Column::Metadata) { - Ok(res) => { - return res.expect( - "get_finalized_da_height value should be always present and set", - ) - } - Err(err) => { - panic!("get_finalized_da_height database corruption, err:{:?}", err); - } - } - } - - async fn set_validators_da_height(&self, block: DaBlockHeight) { - let _: Option = self - .insert(metadata::VALIDATORS_DA_HEIGHT_KEY, Column::Metadata, block) - .unwrap_or_else(|err| { - panic!("set_validators_da_height should always succeed: {:?}", err); - }); - } - - async fn get_validators_da_height(&self) -> DaBlockHeight { - match self.get(metadata::VALIDATORS_DA_HEIGHT_KEY, Column::Metadata) { - Ok(res) => { - return res.expect( - "get_validators_da_height value should be always present and set", - ) - } - Err(err) => { - panic!( - "get_validators_da_height database corruption, err:{:?}", - err - ); - } - } - } - - async fn get_last_committed_finalized_fuel_height(&self) -> BlockHeight { - match self.get( - metadata::LAST_COMMITTED_FINALIZED_BLOCK_HEIGHT_KEY, - Column::Metadata, - ) { - Ok(res) => { - return res - .expect("set_last_committed_finalized_fuel_height value should be always present and set"); - } - Err(err) => { - panic!( - "set_last_committed_finalized_fuel_height database corruption, err:{:?}", - err - ); - } - } - } - - async fn set_last_committed_finalized_fuel_height(&self, block_height: BlockHeight) { - let _: Option = self - .insert( - metadata::LAST_COMMITTED_FINALIZED_BLOCK_HEIGHT_KEY, - Column::Metadata, - block_height, - ) - .unwrap_or_else(|err| { - panic!( - "set_last_committed_finalized_fuel_height should always succeed: {:?}", - err - ); - }); - } -} diff --git a/fuel-core/src/database/storage/staking_diffs.rs b/fuel-core/src/database/staking_diffs.rs similarity index 100% rename from fuel-core/src/database/storage/staking_diffs.rs rename to fuel-core/src/database/staking_diffs.rs diff --git a/fuel-core/src/database/storage/state.rs b/fuel-core/src/database/state.rs similarity index 100% rename from fuel-core/src/database/storage/state.rs rename to fuel-core/src/database/state.rs diff --git a/fuel-core/src/database/storage.rs b/fuel-core/src/database/storage.rs index 0422f95ec16..cf63a8dfaa6 100644 --- a/fuel-core/src/database/storage.rs +++ b/fuel-core/src/database/storage.rs @@ -11,19 +11,6 @@ use fuel_core_interfaces::{ use fuel_crypto::fuel_types::Bytes32; use fuel_txpool::types::ContractId; -pub mod balances; -pub mod block; -pub mod code_root; -pub mod coin; -pub mod contracts; -pub mod delegates_index; -pub mod message; -pub mod receipts; -pub mod staking_diffs; -pub mod state; -pub mod transaction; -pub mod validator_set; - /// The table of blocks generated by Fuels validators. /// Right now, we have only that type of block, but we will support others in the future. pub struct FuelBlocks; diff --git a/fuel-core/src/database/storage/transaction.rs b/fuel-core/src/database/storage/transaction.rs deleted file mode 100644 index c3dda2588e9..00000000000 --- a/fuel-core/src/database/storage/transaction.rs +++ /dev/null @@ -1,140 +0,0 @@ -use crate::{ - database::{ - transaction::{ - OwnedTransactionIndexCursor, - OwnedTransactionIndexKey, - TransactionIndex, - }, - Column, - Database, - KvStoreError, - }, - model::BlockHeight, - state::{ - Error, - IterDirection, - }, - tx_pool::TransactionStatus, -}; -use fuel_core_interfaces::{ - common::{ - fuel_storage::{ - StorageInspect, - StorageMutate, - }, - fuel_tx::{ - Bytes32, - Transaction, - }, - fuel_types::Address, - }, - db::Transactions, -}; -use std::{ - borrow::Cow, - ops::Deref, -}; - -impl StorageInspect for Database { - type Error = KvStoreError; - - fn get(&self, key: &Bytes32) -> Result>, KvStoreError> { - Database::get(self, key.as_ref(), Column::Transaction).map_err(Into::into) - } - - fn contains_key(&self, key: &Bytes32) -> Result { - Database::exists(self, key.as_ref(), Column::Transaction).map_err(Into::into) - } -} - -impl StorageMutate for Database { - fn insert( - &mut self, - key: &Bytes32, - value: &Transaction, - ) -> Result, KvStoreError> { - Database::insert(self, key.as_ref(), Column::Transaction, value.clone()) - .map_err(Into::into) - } - - fn remove(&mut self, key: &Bytes32) -> Result, KvStoreError> { - Database::remove(self, key.as_ref(), Column::Transaction).map_err(Into::into) - } -} - -impl Database { - pub fn all_transactions( - &self, - start: Option<&Bytes32>, - direction: Option, - ) -> impl Iterator> + '_ { - let start = start.map(|b| b.as_ref().to_vec()); - self.iter_all::, Transaction>(Column::Transaction, None, start, direction) - .map(|res| res.map(|(_, tx)| tx)) - } - - /// Iterates over a KV mapping of `[address + block height + tx idx] => transaction id`. This - /// allows for efficient lookup of transaction ids associated with an address, sorted by - /// block age and ordering within a block. The cursor tracks the `[block height + tx idx]` for - /// pagination purposes. - pub fn owned_transactions( - &self, - owner: &Address, - start: Option<&OwnedTransactionIndexCursor>, - direction: Option, - ) -> impl Iterator> + '_ - { - let start = start - .map(|cursor| owned_tx_index_key(owner, cursor.block_height, cursor.tx_idx)); - self.iter_all::( - Column::TransactionsByOwnerBlockIdx, - Some(owner.to_vec()), - start, - direction, - ) - .map(|res| res.map(|(key, tx_id)| (key.into(), tx_id))) - } - - pub fn record_tx_id_owner( - &self, - owner: &Address, - block_height: BlockHeight, - tx_idx: TransactionIndex, - tx_id: &Bytes32, - ) -> Result, Error> { - self.insert( - owned_tx_index_key(owner, block_height, tx_idx), - Column::TransactionsByOwnerBlockIdx, - *tx_id, - ) - } - - pub fn update_tx_status( - &self, - tx_id: &Bytes32, - status: TransactionStatus, - ) -> Result, Error> { - self.insert(tx_id, Column::TransactionStatus, status) - } - - pub fn get_tx_status( - &self, - tx_id: &Bytes32, - ) -> Result, Error> { - self.get(&tx_id.deref()[..], Column::TransactionStatus) - } -} - -fn owned_tx_index_key( - owner: &Address, - height: BlockHeight, - tx_idx: TransactionIndex, -) -> Vec { - // generate prefix to enable sorted indexing of transactions by owner - // owner + block_height + tx_idx - let mut key = Vec::with_capacity(40); - key.extend(owner.as_ref()); - key.extend(height.to_bytes()); - key.extend(tx_idx.to_be_bytes()); - key -} diff --git a/fuel-core/src/database/transaction.rs b/fuel-core/src/database/transaction.rs index 0eea90981c1..a6faebbc768 100644 --- a/fuel-core/src/database/transaction.rs +++ b/fuel-core/src/database/transaction.rs @@ -1,4 +1,140 @@ -use fuel_core_interfaces::model::BlockHeight; +use crate::{ + database::{ + Column, + Database, + KvStoreError, + }, + model::BlockHeight, + state::{ + Error, + IterDirection, + }, + tx_pool::TransactionStatus, +}; +use fuel_core_interfaces::{ + common::{ + fuel_storage::{ + StorageInspect, + StorageMutate, + }, + fuel_tx::{ + Bytes32, + Transaction, + }, + fuel_types::Address, + }, + db::Transactions, +}; +use std::{ + borrow::Cow, + ops::Deref, +}; + +impl StorageInspect for Database { + type Error = KvStoreError; + + fn get(&self, key: &Bytes32) -> Result>, KvStoreError> { + Database::get(self, key.as_ref(), Column::Transaction).map_err(Into::into) + } + + fn contains_key(&self, key: &Bytes32) -> Result { + Database::exists(self, key.as_ref(), Column::Transaction).map_err(Into::into) + } +} + +impl StorageMutate for Database { + fn insert( + &mut self, + key: &Bytes32, + value: &Transaction, + ) -> Result, KvStoreError> { + Database::insert(self, key.as_ref(), Column::Transaction, value.clone()) + .map_err(Into::into) + } + + fn remove(&mut self, key: &Bytes32) -> Result, KvStoreError> { + Database::remove(self, key.as_ref(), Column::Transaction).map_err(Into::into) + } +} + +impl Database { + pub fn all_transactions( + &self, + start: Option<&Bytes32>, + direction: Option, + ) -> impl Iterator> + '_ { + let start = start.map(|b| b.as_ref().to_vec()); + self.iter_all::, Transaction>(Column::Transaction, None, start, direction) + .map(|res| res.map(|(_, tx)| tx)) + } + + /// Iterates over a KV mapping of `[address + block height + tx idx] => transaction id`. This + /// allows for efficient lookup of transaction ids associated with an address, sorted by + /// block age and ordering within a block. The cursor tracks the `[block height + tx idx]` for + /// pagination purposes. + pub fn owned_transactions( + &self, + owner: &Address, + start: Option<&OwnedTransactionIndexCursor>, + direction: Option, + ) -> impl Iterator> + '_ + { + let start = start + .map(|cursor| owned_tx_index_key(owner, cursor.block_height, cursor.tx_idx)); + self.iter_all::( + Column::TransactionsByOwnerBlockIdx, + Some(owner.to_vec()), + start, + direction, + ) + .map(|res| res.map(|(key, tx_id)| (key.into(), tx_id))) + } + + pub fn record_tx_id_owner( + &self, + owner: &Address, + block_height: BlockHeight, + tx_idx: TransactionIndex, + tx_id: &Bytes32, + ) -> Result, Error> { + self.insert( + owned_tx_index_key(owner, block_height, tx_idx), + Column::TransactionsByOwnerBlockIdx, + *tx_id, + ) + } + + pub fn update_tx_status( + &self, + tx_id: &Bytes32, + status: TransactionStatus, + ) -> Result, Error> { + self.insert(tx_id, Column::TransactionStatus, status) + } + + pub fn get_tx_status( + &self, + tx_id: &Bytes32, + ) -> Result, Error> { + self.get(&tx_id.deref()[..], Column::TransactionStatus) + } +} + +fn owned_tx_index_key( + owner: &Address, + height: BlockHeight, + tx_idx: TransactionIndex, +) -> Vec { + // generate prefix to enable sorted indexing of transactions by owner + // owner + block_height + tx_idx + let mut key = Vec::with_capacity(40); + key.extend(owner.as_ref()); + key.extend(height.to_bytes()); + key.extend(tx_idx.to_be_bytes()); + key +} + +////////////////////////////////////// Not storage part ////////////////////////////////////// pub type TransactionIndex = u32; diff --git a/fuel-core/src/database/storage/validator_set.rs b/fuel-core/src/database/validator_set.rs similarity index 100% rename from fuel-core/src/database/storage/validator_set.rs rename to fuel-core/src/database/validator_set.rs diff --git a/fuel-core/src/state/rocks_db.rs b/fuel-core/src/state/rocks_db.rs index 50e070cf451..6ae96529f85 100644 --- a/fuel-core/src/state/rocks_db.rs +++ b/fuel-core/src/state/rocks_db.rs @@ -1,5 +1,3 @@ -#[cfg(feature = "prometheus")] -use crate::service::metrics::prometheus_metrics::DATABASE_METRICS; use crate::{ database::{ metadata::{ @@ -18,6 +16,8 @@ use crate::{ WriteOperation, }, }; +#[cfg(feature = "metrics")] +use fuel_metrics::core_metrics::DATABASE_METRICS; use rocksdb::{ BoundColumnFamily, ColumnFamilyDescriptor, @@ -129,13 +129,13 @@ impl RocksDb { impl KeyValueStore for RocksDb { fn get(&self, key: &[u8], column: Column) -> crate::state::Result>> { - #[cfg(feature = "prometheus")] + #[cfg(feature = "metrics")] DATABASE_METRICS.read_meter.inc(); let value = self .db .get_cf(&self.cf(column), key) .map_err(|e| Error::DatabaseError(Box::new(e))); - #[cfg(feature = "prometheus")] + #[cfg(feature = "metrics")] { if value.is_ok() && value.as_ref().unwrap().is_some() { let value_as_vec = value.as_ref().cloned().unwrap().unwrap(); @@ -153,7 +153,7 @@ impl KeyValueStore for RocksDb { column: Column, value: Vec, ) -> crate::state::Result>> { - #[cfg(feature = "prometheus")] + #[cfg(feature = "metrics")] { DATABASE_METRICS.write_meter.inc(); DATABASE_METRICS @@ -226,7 +226,7 @@ impl KeyValueStore for RocksDb { item.map(|(key, value)| { let value_as_vec = value.to_vec(); let key_as_vec = key.to_vec(); - #[cfg(feature = "prometheus")] + #[cfg(feature = "metrics")] { DATABASE_METRICS.read_meter.inc(); DATABASE_METRICS @@ -271,7 +271,7 @@ impl BatchOperations for RocksDb { } } } - #[cfg(feature = "prometheus")] + #[cfg(feature = "metrics")] { DATABASE_METRICS.write_meter.inc(); DATABASE_METRICS From 9b6d2e0759ed375484df6aa7155e1ffc3db7f685 Mon Sep 17 00:00:00 2001 From: green Date: Sat, 10 Sep 2022 00:40:54 +0100 Subject: [PATCH 4/7] Updated `fuel-tx` to `0.20`. Updated `fuel-vm` to `0.18`. Renamed all columns to be according with the table. Added description to each `Column`. Added more description to tables. --- Cargo.lock | 40 ++++++----------------- fuel-client/Cargo.toml | 4 +-- fuel-core-interfaces/Cargo.toml | 4 +-- fuel-core-interfaces/src/db.rs | 4 +-- fuel-core-interfaces/src/model/coin.rs | 4 +++ fuel-core/src/database.rs | 40 +++++++++++++++-------- fuel-core/src/database/balances.rs | 10 +++--- fuel-core/src/database/block.rs | 24 +++++++++----- fuel-core/src/database/contracts.rs | 12 +++---- fuel-core/src/database/delegates_index.rs | 8 ++--- fuel-core/src/database/transaction.rs | 17 ++++++---- fuel-core/src/database/validator_set.rs | 8 ++--- 12 files changed, 92 insertions(+), 83 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index af789208d2c..a37fad866a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2188,8 +2188,8 @@ dependencies = [ "derive_more", "fuel-asm", "fuel-crypto", - "fuel-merkle 0.4.0", - "fuel-storage 0.3.0", + "fuel-merkle", + "fuel-storage", "fuel-tx", "fuel-types", "fuel-vm", @@ -2241,20 +2241,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "fuel-merkle" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa59f2a4e6cd6d83a51981c5ac706d58fc8ef53700003948c826827b88cfff1" -dependencies = [ - "digest 0.10.3", - "fuel-storage 0.2.0", - "hashbrown", - "hex", - "sha2 0.10.2", - "thiserror", -] - [[package]] name = "fuel-merkle" version = "0.4.0" @@ -2262,7 +2248,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c006505ab44132df81c7b38a438a3b8b5ec368b93f9294dcc75ee381c6939655" dependencies = [ "digest 0.10.3", - "fuel-storage 0.3.0", + "fuel-storage", "hashbrown", "hex", "sha2 0.10.2", @@ -2334,12 +2320,6 @@ dependencies = [ "url", ] -[[package]] -name = "fuel-storage" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34b9161e86d434a93088409530a4f71f42e074b3bbcbb7a27bfe666583f92fd7" - [[package]] name = "fuel-storage" version = "0.3.0" @@ -2380,13 +2360,13 @@ dependencies = [ [[package]] name = "fuel-tx" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d88b96bddf1c57f1d73a51f0f58ef67b294cdb722d5f80ee76d9cf84b986769e" +checksum = "e9045f94a95dda991ae16f8a4720cf6c1f5112c9911173726ed702eb4cb70204" dependencies = [ "fuel-asm", "fuel-crypto", - "fuel-merkle 0.3.0", + "fuel-merkle", "fuel-types", "itertools", "num-integer", @@ -2422,15 +2402,15 @@ dependencies = [ [[package]] name = "fuel-vm" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6658f32707cb114d464561ed6e304e9830da6a4e74da3e5fcdab4aad94d81361" +checksum = "6ceb5384b74f8518f29e230af43a2cec64f51004e08d21d990090c622db96012" dependencies = [ "anyhow", "fuel-asm", "fuel-crypto", - "fuel-merkle 0.4.0", - "fuel-storage 0.3.0", + "fuel-merkle", + "fuel-storage", "fuel-tx", "fuel-types", "itertools", diff --git a/fuel-client/Cargo.toml b/fuel-client/Cargo.toml index f824361848a..c9fba4ef488 100644 --- a/fuel-client/Cargo.toml +++ b/fuel-client/Cargo.toml @@ -20,9 +20,9 @@ chrono = { version = "0.4", features = ["serde"] } clap = { version = "3.1", features = ["derive"] } cynic = { version = "1.0", features = ["surf"] } derive_more = { version = "0.99" } -fuel-tx = { version = "0.19", features = ["serde"] } +fuel-tx = { version = "0.20", features = ["serde"] } fuel-types = { version = "0.5", features = ["serde"] } -fuel-vm = { version = "0.17", features = ["serde"] } +fuel-vm = { version = "0.18", features = ["serde"] } futures = "0.3" hex = "0.4" itertools = "0.10" diff --git a/fuel-core-interfaces/Cargo.toml b/fuel-core-interfaces/Cargo.toml index 0b601d90a16..51b4a6d243c 100644 --- a/fuel-core-interfaces/Cargo.toml +++ b/fuel-core-interfaces/Cargo.toml @@ -19,9 +19,9 @@ fuel-asm = "0.9" fuel-crypto = { version = "0.6", default-features = false, features = [ "random" ] } fuel-merkle = "0.4" fuel-storage = "0.3" -fuel-tx = { version = "0.19", default-features = false } +fuel-tx = { version = "0.20", default-features = false } fuel-types = { version = "0.5", default-features = false } -fuel-vm = { version = "0.17", default-features = false } +fuel-vm = { version = "0.18", default-features = false } futures = "0.3" lazy_static = "1.4" parking_lot = "0.12" diff --git a/fuel-core-interfaces/src/db.rs b/fuel-core-interfaces/src/db.rs index fbc40a4e018..87a98057ff0 100644 --- a/fuel-core-interfaces/src/db.rs +++ b/fuel-core-interfaces/src/db.rs @@ -30,7 +30,7 @@ pub use fuel_vm::storage::{ ContractsState, }; -/// The storage table of coins UTXOs. +/// The storage table of coins. Each [`Coin`](crate::model::Coin) is represented by unique `UtxoId`. pub struct Coins; impl Mappable for Coins { @@ -39,7 +39,7 @@ impl Mappable for Coins { type GetValue = Self::SetValue; } -/// The storage table of bridget from Ethereum messages. +/// The storage table of bridget from the Ethereum [`Message`](crate::model::Message)s. pub struct Messages; impl Mappable for Messages { diff --git a/fuel-core-interfaces/src/model/coin.rs b/fuel-core-interfaces/src/model/coin.rs index d295d7a5808..07242fc6bf0 100644 --- a/fuel-core-interfaces/src/model/coin.rs +++ b/fuel-core-interfaces/src/model/coin.rs @@ -7,6 +7,10 @@ use fuel_tx::{ AssetId, }; +/// Represents the user's coin for some asset with `asset_id`. +/// The `Coin` is either `CoinStatus::Spent` or `CoinStatus::Unspent`. If the coin is unspent, +/// it can be used as an input to the transaction and can be spent up to the `amount`. +/// After usage as an input of the transaction, the `Coin` become `CoinStatus::Spent`. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, Clone)] pub struct Coin { diff --git a/fuel-core/src/database.rs b/fuel-core/src/database.rs index f3bcb6b063d..cf11d1bea14 100644 --- a/fuel-core/src/database.rs +++ b/fuel-core/src/database.rs @@ -76,32 +76,46 @@ pub mod transactional; Copy, Clone, Debug, strum_macros::EnumCount, PartialEq, Eq, enum_iterator::Sequence, )] pub enum Column { + /// The column id of metadata about the blockchain Metadata = 0, + /// See [`ContractsRawCode`](fuel_vm::storage::ContractsRawCode) ContractsRawCode = 1, + /// See [`ContractsRawCode`](fuel_vm::storage::ContractsRawCode) ContractsInfo = 2, + /// See [`ContractsState`](fuel_vm::storage::ContractsState) ContractsState = 3, - /// Contract Id -> Utxo Id - ContractUtxoId = 4, - Balances = 5, + /// See [`ContractsLatestUtxo`](storage::ContractsLatestUtxo) + ContractsLatestUtxo = 4, + /// See [`ContractsAssets`](fuel_vm::storage::ContractsAssets) + ContractsAssets = 5, + /// See [`Coins`](fuel_core_interfaces::db::Coins) Coins = 6, - /// (owner, coin id) => true + /// The column of the table that stores `true` if `owner` owns `Coin` with `coin_id` OwnedCoins = 7, - Transaction = 8, - /// tx id -> current status + /// See [`Transactions`](fuel_core_interfaces::db::Transactions) + Transactions = 8, + /// Transaction id to current status TransactionStatus = 9, + /// The column of the table of all `owner`'s transactions TransactionsByOwnerBlockIdx = 10, + /// See [`Receipts`](storage::Receipts) Receipts = 11, - Blocks = 12, - /// Maps block id to block hash - BlockIds = 13, + /// See [`FuelBlocks`](storage::FuelBlocks) + FuelBlocks = 12, + /// Maps fuel block id to fuel block hash + FuelBlockIds = 13, + /// See [`Messages`](fuel_core_interfaces::db::Messages) Messages = 14, /// Contain current validator stake and it consensus_key if set. - ValidatorSet = 15, + /// See [`ValidatorsSet`](fuel_core_interfaces::db::ValidatorsSet) + ValidatorsSet = 15, /// Contain diff between da blocks it contains new registers consensus key and new delegate sets. + /// See [`StackingDiffs`](fuel_core_interfaces::db::StackingDiffs) StackingDiffs = 16, /// Maps delegate address with validator_set_diff index where last delegate change happened. - DelegatesIndex = 17, - /// (Owner, MessageId) => true + /// See [`DelegatesIndexes`](fuel_core_interfaces::db::DelegatesIndexes) + DelegatesIndexes = 17, + /// The column of the table that stores `true` if `owner` owns `Message` with `message_id` OwnedMessageIds = 18, } @@ -365,7 +379,7 @@ mod relayer { let mut out = HashMap::new(); for diff in self .iter_all::)>( - Column::ValidatorSet, + Column::ValidatorsSet, None, None, None, diff --git a/fuel-core/src/database/balances.rs b/fuel-core/src/database/balances.rs index 48cef1134c7..1d9790fe9f5 100644 --- a/fuel-core/src/database/balances.rs +++ b/fuel-core/src/database/balances.rs @@ -36,12 +36,12 @@ impl StorageInspect> for Database { fn get(&self, key: &(&ContractId, &AssetId)) -> Result>, Error> { let key = MultiKey::new(key); - self.get(key.as_ref(), Column::Balances) + self.get(key.as_ref(), Column::ContractsAssets) } fn contains_key(&self, key: &(&ContractId, &AssetId)) -> Result { let key = MultiKey::new(key); - self.exists(key.as_ref(), Column::Balances) + self.exists(key.as_ref(), Column::ContractsAssets) } } @@ -52,12 +52,12 @@ impl StorageMutate> for Database { value: &Word, ) -> Result, Error> { let key = MultiKey::new(key); - Database::insert(self, key.as_ref(), Column::Balances, *value) + Database::insert(self, key.as_ref(), Column::ContractsAssets, *value) } fn remove(&mut self, key: &(&ContractId, &AssetId)) -> Result, Error> { let key = MultiKey::new(key); - Database::remove(self, key.as_ref(), Column::Balances) + Database::remove(self, key.as_ref(), Column::ContractsAssets) } } @@ -65,7 +65,7 @@ impl MerkleRootStorage> for Database { fn root(&mut self, parent: &ContractId) -> Result { let items: Vec<_> = Database::iter_all::, Word>( self, - Column::Balances, + Column::ContractsAssets, Some(parent.as_ref().to_vec()), None, Some(IterDirection::Forward), diff --git a/fuel-core/src/database/block.rs b/fuel-core/src/database/block.rs index a84be10f7a8..9584b5fd81d 100644 --- a/fuel-core/src/database/block.rs +++ b/fuel-core/src/database/block.rs @@ -33,11 +33,11 @@ impl StorageInspect for Database { type Error = KvStoreError; fn get(&self, key: &Bytes32) -> Result>, KvStoreError> { - Database::get(self, key.as_ref(), Column::Blocks).map_err(Into::into) + Database::get(self, key.as_ref(), Column::FuelBlocks).map_err(Into::into) } fn contains_key(&self, key: &Bytes32) -> Result { - Database::exists(self, key.as_ref(), Column::Blocks).map_err(Into::into) + Database::exists(self, key.as_ref(), Column::FuelBlocks).map_err(Into::into) } } @@ -50,20 +50,21 @@ impl StorageMutate for Database { let _: Option = Database::insert( self, value.headers.height.to_be_bytes(), - Column::BlockIds, + Column::FuelBlockIds, *key, )?; - Database::insert(self, key.as_ref(), Column::Blocks, value).map_err(Into::into) + Database::insert(self, key.as_ref(), Column::FuelBlocks, value) + .map_err(Into::into) } fn remove(&mut self, key: &Bytes32) -> Result, KvStoreError> { let block: Option = - Database::remove(self, key.as_ref(), Column::Blocks)?; + Database::remove(self, key.as_ref(), Column::FuelBlocks)?; if let Some(block) = &block { let _: Option = Database::remove( self, &block.headers.height.to_be_bytes(), - Column::BlockIds, + Column::FuelBlockIds, )?; } Ok(block) @@ -73,7 +74,12 @@ impl StorageMutate for Database { impl Database { pub fn get_block_height(&self) -> Result, Error> { let block_entry: Option<(Vec, Bytes32)> = self - .iter_all(Column::BlockIds, None, None, Some(IterDirection::Reverse)) + .iter_all( + Column::FuelBlockIds, + None, + None, + Some(IterDirection::Reverse), + ) .next() .transpose()?; // get block height from most recently indexed block @@ -90,7 +96,7 @@ impl Database { } pub fn get_block_id(&self, height: BlockHeight) -> Result, Error> { - Database::get(self, &height.to_bytes()[..], Column::BlockIds) + Database::get(self, &height.to_bytes()[..], Column::FuelBlockIds) } pub fn all_block_ids( @@ -99,7 +105,7 @@ impl Database { direction: Option, ) -> impl Iterator> + '_ { let start = start.map(|b| b.to_bytes().to_vec()); - self.iter_all::, Bytes32>(Column::BlockIds, None, start, direction) + self.iter_all::, Bytes32>(Column::FuelBlockIds, None, start, direction) .map(|res| { let (height, id) = res?; Ok(( diff --git a/fuel-core/src/database/contracts.rs b/fuel-core/src/database/contracts.rs index 77b11a73a59..9f198da816b 100644 --- a/fuel-core/src/database/contracts.rs +++ b/fuel-core/src/database/contracts.rs @@ -64,11 +64,11 @@ impl StorageInspect for Database { type Error = Error; fn get(&self, key: &ContractId) -> Result>, Self::Error> { - self.get(key.as_ref(), Column::ContractUtxoId) + self.get(key.as_ref(), Column::ContractsLatestUtxo) } fn contains_key(&self, key: &ContractId) -> Result { - self.exists(key.as_ref(), Column::ContractUtxoId) + self.exists(key.as_ref(), Column::ContractsLatestUtxo) } } @@ -78,11 +78,11 @@ impl StorageMutate for Database { key: &ContractId, value: &UtxoId, ) -> Result, Self::Error> { - Database::insert(self, key.as_ref(), Column::ContractUtxoId, *value) + Database::insert(self, key.as_ref(), Column::ContractsLatestUtxo, *value) } fn remove(&mut self, key: &ContractId) -> Result, Self::Error> { - Database::remove(self, key.as_ref(), Column::ContractUtxoId) + Database::remove(self, key.as_ref(), Column::ContractsLatestUtxo) } } @@ -94,7 +94,7 @@ impl Database { direction: Option, ) -> impl Iterator> + '_ { self.iter_all::, Word>( - Column::Balances, + Column::ContractsAssets, Some(contract.as_ref().to_vec()), start_asset .map(|asset_id| MultiKey::new(&(&contract, &asset_id)).as_ref().to_vec()), @@ -150,7 +150,7 @@ impl Database { let balances = Some( self.iter_all::, u64>( - Column::Balances, + Column::ContractsAssets, Some(contract_id.as_ref().to_vec()), None, None, diff --git a/fuel-core/src/database/delegates_index.rs b/fuel-core/src/database/delegates_index.rs index fc1431c69b3..88997d791ab 100644 --- a/fuel-core/src/database/delegates_index.rs +++ b/fuel-core/src/database/delegates_index.rs @@ -23,11 +23,11 @@ impl StorageInspect for Database { &self, key: &Address, ) -> Result>>, KvStoreError> { - Database::get(self, key.as_ref(), Column::DelegatesIndex).map_err(Into::into) + Database::get(self, key.as_ref(), Column::DelegatesIndexes).map_err(Into::into) } fn contains_key(&self, key: &Address) -> Result { - Database::exists(self, key.as_ref(), Column::DelegatesIndex).map_err(Into::into) + Database::exists(self, key.as_ref(), Column::DelegatesIndexes).map_err(Into::into) } } @@ -37,7 +37,7 @@ impl StorageMutate for Database { key: &Address, value: &[DaBlockHeight], ) -> Result>, KvStoreError> { - Database::insert(self, key.as_ref(), Column::DelegatesIndex, value) + Database::insert(self, key.as_ref(), Column::DelegatesIndexes, value) .map_err(Into::into) } @@ -45,6 +45,6 @@ impl StorageMutate for Database { &mut self, key: &Address, ) -> Result>, KvStoreError> { - Database::remove(self, key.as_ref(), Column::DelegatesIndex).map_err(Into::into) + Database::remove(self, key.as_ref(), Column::DelegatesIndexes).map_err(Into::into) } } diff --git a/fuel-core/src/database/transaction.rs b/fuel-core/src/database/transaction.rs index a6faebbc768..dd49ee6d9db 100644 --- a/fuel-core/src/database/transaction.rs +++ b/fuel-core/src/database/transaction.rs @@ -34,11 +34,11 @@ impl StorageInspect for Database { type Error = KvStoreError; fn get(&self, key: &Bytes32) -> Result>, KvStoreError> { - Database::get(self, key.as_ref(), Column::Transaction).map_err(Into::into) + Database::get(self, key.as_ref(), Column::Transactions).map_err(Into::into) } fn contains_key(&self, key: &Bytes32) -> Result { - Database::exists(self, key.as_ref(), Column::Transaction).map_err(Into::into) + Database::exists(self, key.as_ref(), Column::Transactions).map_err(Into::into) } } @@ -48,12 +48,12 @@ impl StorageMutate for Database { key: &Bytes32, value: &Transaction, ) -> Result, KvStoreError> { - Database::insert(self, key.as_ref(), Column::Transaction, value.clone()) + Database::insert(self, key.as_ref(), Column::Transactions, value.clone()) .map_err(Into::into) } fn remove(&mut self, key: &Bytes32) -> Result, KvStoreError> { - Database::remove(self, key.as_ref(), Column::Transaction).map_err(Into::into) + Database::remove(self, key.as_ref(), Column::Transactions).map_err(Into::into) } } @@ -64,8 +64,13 @@ impl Database { direction: Option, ) -> impl Iterator> + '_ { let start = start.map(|b| b.as_ref().to_vec()); - self.iter_all::, Transaction>(Column::Transaction, None, start, direction) - .map(|res| res.map(|(_, tx)| tx)) + self.iter_all::, Transaction>( + Column::Transactions, + None, + start, + direction, + ) + .map(|res| res.map(|(_, tx)| tx)) } /// Iterates over a KV mapping of `[address + block height + tx idx] => transaction id`. This diff --git a/fuel-core/src/database/validator_set.rs b/fuel-core/src/database/validator_set.rs index 5b8aa48f92e..b93c3315287 100644 --- a/fuel-core/src/database/validator_set.rs +++ b/fuel-core/src/database/validator_set.rs @@ -24,11 +24,11 @@ impl StorageInspect for Database { &self, key: &ValidatorId, ) -> Result)>>, KvStoreError> { - Database::get(self, key.as_ref(), Column::ValidatorSet).map_err(Into::into) + Database::get(self, key.as_ref(), Column::ValidatorsSet).map_err(Into::into) } fn contains_key(&self, key: &ValidatorId) -> Result { - Database::exists(self, key.as_ref(), Column::ValidatorSet).map_err(Into::into) + Database::exists(self, key.as_ref(), Column::ValidatorsSet).map_err(Into::into) } } @@ -38,7 +38,7 @@ impl StorageMutate for Database { key: &ValidatorId, value: &(ValidatorStake, Option), ) -> Result)>, KvStoreError> { - Database::insert(self, key.as_ref(), Column::ValidatorSet, value) + Database::insert(self, key.as_ref(), Column::ValidatorsSet, value) .map_err(Into::into) } @@ -46,6 +46,6 @@ impl StorageMutate for Database { &mut self, key: &ValidatorId, ) -> Result)>, KvStoreError> { - Database::remove(self, key.as_ref(), Column::ValidatorSet).map_err(Into::into) + Database::remove(self, key.as_ref(), Column::ValidatorsSet).map_err(Into::into) } } From db4b4d04353a42bcee18ea98b936d415cd4d77c0 Mon Sep 17 00:00:00 2001 From: green Date: Mon, 12 Sep 2022 11:19:52 +0100 Subject: [PATCH 5/7] Fixing the compilation issues after the merge --- fuel-core-interfaces/src/txpool.rs | 2 -- fuel-core-interfaces/src/utils.rs | 10 ++++++---- fuel-core/src/database/storage.rs | 2 +- fuel-core/src/service/genesis.rs | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/fuel-core-interfaces/src/txpool.rs b/fuel-core-interfaces/src/txpool.rs index 5a12befcb7d..a939a6c89cf 100644 --- a/fuel-core-interfaces/src/txpool.rs +++ b/fuel-core-interfaces/src/txpool.rs @@ -1,7 +1,6 @@ use crate::{ common::{ fuel_storage::{ - Storage, StorageAsRef, StorageInspect, }, @@ -13,7 +12,6 @@ use crate::{ }, fuel_types::MessageId, fuel_vm::storage::ContractsRawCode, - prelude::Contract, }, db::{ Coins, diff --git a/fuel-core-interfaces/src/utils.rs b/fuel-core-interfaces/src/utils.rs index 84300ffb53a..32321dc382d 100644 --- a/fuel-core-interfaces/src/utils.rs +++ b/fuel-core-interfaces/src/utils.rs @@ -1,9 +1,11 @@ pub mod signer { - use crate::signer::{ - Signer, - SignerError, + use crate::{ + common::fuel_types::Bytes32, + signer::{ + Signer, + SignerError, + }, }; - use fuel_types::Bytes32; pub struct DummySigner {} diff --git a/fuel-core/src/database/storage.rs b/fuel-core/src/database/storage.rs index cf63a8dfaa6..2fed9d8e862 100644 --- a/fuel-core/src/database/storage.rs +++ b/fuel-core/src/database/storage.rs @@ -1,5 +1,6 @@ use fuel_core_interfaces::{ common::{ + fuel_crypto::fuel_types::Bytes32, fuel_storage::Mappable, fuel_tx::{ Receipt, @@ -8,7 +9,6 @@ use fuel_core_interfaces::{ }, model::FuelBlockDb, }; -use fuel_crypto::fuel_types::Bytes32; use fuel_txpool::types::ContractId; /// The table of blocks generated by Fuels validators. diff --git a/fuel-core/src/service/genesis.rs b/fuel-core/src/service/genesis.rs index 5fc706102db..858e26c9f93 100644 --- a/fuel-core/src/service/genesis.rs +++ b/fuel-core/src/service/genesis.rs @@ -223,6 +223,7 @@ mod tests { use fuel_core_interfaces::{ common::{ fuel_asm::Opcode, + fuel_crypto::fuel_types::Salt, fuel_storage::StorageAsRef, fuel_types::{ Address, @@ -232,7 +233,6 @@ mod tests { db::Coins, model::Message, }; - use fuel_crypto::fuel_types::Salt; use itertools::Itertools; use rand::{ rngs::StdRng, From 9292505f363c4db7778515df000d9e2588b792f3 Mon Sep 17 00:00:00 2001 From: green Date: Tue, 13 Sep 2022 23:56:39 +0100 Subject: [PATCH 6/7] Applied suggestions from teh review. --- fuel-core-interfaces/src/db.rs | 8 ++++---- fuel-core-interfaces/src/lib.rs | 2 -- fuel-core-interfaces/src/model/coin.rs | 2 +- fuel-core-interfaces/src/relayer.rs | 8 ++++---- fuel-core-interfaces/src/signer.rs | 14 ++++++++++++++ fuel-core-interfaces/src/utils.rs | 18 ------------------ fuel-core/src/database.rs | 6 +++--- fuel-core/src/database/staking_diffs.rs | 21 ++++++++------------- fuel-relayer/src/mock_db.rs | 6 +++--- 9 files changed, 37 insertions(+), 48 deletions(-) delete mode 100644 fuel-core-interfaces/src/utils.rs diff --git a/fuel-core-interfaces/src/db.rs b/fuel-core-interfaces/src/db.rs index 590def3c3b4..5060797d628 100644 --- a/fuel-core-interfaces/src/db.rs +++ b/fuel-core-interfaces/src/db.rs @@ -40,7 +40,7 @@ impl Mappable for Coins { type GetValue = Self::SetValue; } -/// The storage table of bridget from the Ethereum [`Message`](crate::model::Message)s. +/// The storage table of bridged Ethereum [`Message`](crate::model::Message)s. pub struct Messages; impl Mappable for Messages { @@ -77,10 +77,10 @@ impl Mappable for ValidatorsSet { type GetValue = Self::SetValue; } -/// The storage table of relayer stacking diffs. -pub struct StackingDiffs; +/// The storage table of relayer staking diffs. +pub struct StakingDiffs; -impl Mappable for StackingDiffs { +impl Mappable for StakingDiffs { type Key = DaBlockHeight; type SetValue = StakingDiff; type GetValue = Self::SetValue; diff --git a/fuel-core-interfaces/src/lib.rs b/fuel-core-interfaces/src/lib.rs index 8ef16b3e7b7..84550db38c7 100644 --- a/fuel-core-interfaces/src/lib.rs +++ b/fuel-core-interfaces/src/lib.rs @@ -8,8 +8,6 @@ pub mod relayer; pub mod signer; pub mod sync; pub mod txpool; -#[cfg(any(test, feature = "test-helpers"))] -pub mod utils; pub mod common { #[doc(no_inline)] diff --git a/fuel-core-interfaces/src/model/coin.rs b/fuel-core-interfaces/src/model/coin.rs index 5e52b9fcccb..e0a74dfd012 100644 --- a/fuel-core-interfaces/src/model/coin.rs +++ b/fuel-core-interfaces/src/model/coin.rs @@ -14,7 +14,7 @@ use async_graphql::Enum; /// Represents the user's coin for some asset with `asset_id`. /// The `Coin` is either `CoinStatus::Spent` or `CoinStatus::Unspent`. If the coin is unspent, /// it can be used as an input to the transaction and can be spent up to the `amount`. -/// After usage as an input of the transaction, the `Coin` become `CoinStatus::Spent`. +/// After usage as an input of a transaction, the `Coin` becomes `CoinStatus::Spent`. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, Clone)] pub struct Coin { diff --git a/fuel-core-interfaces/src/relayer.rs b/fuel-core-interfaces/src/relayer.rs index 46c759bc63b..a110038799c 100644 --- a/fuel-core-interfaces/src/relayer.rs +++ b/fuel-core-interfaces/src/relayer.rs @@ -10,7 +10,7 @@ use crate::{ DelegatesIndexes, KvStoreError, Messages, - StackingDiffs, + StakingDiffs, ValidatorsSet, }, model::{ @@ -78,7 +78,7 @@ pub trait RelayerDb: StorageMutate + StorageMutate + StorageMutate - + StorageMutate + + StorageMutate + Send + Sync { @@ -95,7 +95,7 @@ pub trait RelayerDb: da_height: DaBlockHeight, stakes: &StakingDiff, ) { - let _ = self.storage::().insert(&da_height, stakes); + let _ = self.storage::().insert(&da_height, stakes); } /// Query delegate index to find list of blocks that delegation changed @@ -123,7 +123,7 @@ pub trait RelayerDb: } // get staking diff let staking_diff = self - .storage::() + .storage::() .get(&last_da_height) .expect("Expect to get data without problem")?; diff --git a/fuel-core-interfaces/src/signer.rs b/fuel-core-interfaces/src/signer.rs index 00a269f56f8..c1e64a8cdf6 100644 --- a/fuel-core-interfaces/src/signer.rs +++ b/fuel-core-interfaces/src/signer.rs @@ -14,3 +14,17 @@ pub enum SignerError { #[error("Private key not loaded")] KeyNotLoaded, } + +#[cfg(any(test, feature = "test-helpers"))] +pub mod helpers { + use super::*; + + pub struct DummySigner {} + + #[async_trait] + impl Signer for DummySigner { + async fn sign(&self, hash: &Bytes32) -> Result { + Ok(*hash) + } + } +} diff --git a/fuel-core-interfaces/src/utils.rs b/fuel-core-interfaces/src/utils.rs deleted file mode 100644 index 32321dc382d..00000000000 --- a/fuel-core-interfaces/src/utils.rs +++ /dev/null @@ -1,18 +0,0 @@ -pub mod signer { - use crate::{ - common::fuel_types::Bytes32, - signer::{ - Signer, - SignerError, - }, - }; - - pub struct DummySigner {} - - #[async_trait::async_trait] - impl Signer for DummySigner { - async fn sign(&self, hash: &Bytes32) -> Result { - Ok(*hash) - } - } -} diff --git a/fuel-core/src/database.rs b/fuel-core/src/database.rs index cf11d1bea14..25948625fbc 100644 --- a/fuel-core/src/database.rs +++ b/fuel-core/src/database.rs @@ -110,8 +110,8 @@ pub enum Column { /// See [`ValidatorsSet`](fuel_core_interfaces::db::ValidatorsSet) ValidatorsSet = 15, /// Contain diff between da blocks it contains new registers consensus key and new delegate sets. - /// See [`StackingDiffs`](fuel_core_interfaces::db::StackingDiffs) - StackingDiffs = 16, + /// See [`StakingDiffs`](fuel_core_interfaces::db::StakingDiffs) + StakingDiffs = 16, /// Maps delegate address with validator_set_diff index where last delegate change happened. /// See [`DelegatesIndexes`](fuel_core_interfaces::db::DelegatesIndexes) DelegatesIndexes = 17, @@ -422,7 +422,7 @@ mod relayer { } let mut out = Vec::new(); for diff in self.iter_all::( - Column::StackingDiffs, + Column::StakingDiffs, None, Some(from_da_height.to_be_bytes().to_vec()), None, diff --git a/fuel-core/src/database/staking_diffs.rs b/fuel-core/src/database/staking_diffs.rs index 6c1c823069b..23d766a94b8 100644 --- a/fuel-core/src/database/staking_diffs.rs +++ b/fuel-core/src/database/staking_diffs.rs @@ -8,45 +8,40 @@ use fuel_core_interfaces::{ StorageInspect, StorageMutate, }, - db::StackingDiffs, + db::StakingDiffs, model::DaBlockHeight, relayer::StakingDiff, }; use std::borrow::Cow; -impl StorageInspect for Database { +impl StorageInspect for Database { type Error = KvStoreError; fn get(&self, key: &DaBlockHeight) -> Result>, KvStoreError> { - Database::get(self, &key.to_be_bytes(), Column::StackingDiffs).map_err(Into::into) + Database::get(self, &key.to_be_bytes(), Column::StakingDiffs).map_err(Into::into) } fn contains_key(&self, key: &DaBlockHeight) -> Result { - Database::exists(self, &key.to_be_bytes(), Column::StackingDiffs) + Database::exists(self, &key.to_be_bytes(), Column::StakingDiffs) .map_err(Into::into) } } -impl StorageMutate for Database { +impl StorageMutate for Database { fn insert( &mut self, key: &DaBlockHeight, value: &StakingDiff, ) -> Result, KvStoreError> { - Database::insert( - self, - key.to_be_bytes(), - Column::StackingDiffs, - value.clone(), - ) - .map_err(Into::into) + Database::insert(self, key.to_be_bytes(), Column::StakingDiffs, value.clone()) + .map_err(Into::into) } fn remove( &mut self, key: &DaBlockHeight, ) -> Result, KvStoreError> { - Database::remove(self, &key.to_be_bytes(), Column::StackingDiffs) + Database::remove(self, &key.to_be_bytes(), Column::StakingDiffs) .map_err(Into::into) } } diff --git a/fuel-relayer/src/mock_db.rs b/fuel-relayer/src/mock_db.rs index ac51401142e..3f70533c5fc 100644 --- a/fuel-relayer/src/mock_db.rs +++ b/fuel-relayer/src/mock_db.rs @@ -27,7 +27,7 @@ use fuel_core_interfaces::{ DelegatesIndexes, KvStoreError, Messages, - StackingDiffs, + StakingDiffs, ValidatorsSet, }, model::{ @@ -191,7 +191,7 @@ impl StorageMutate for MockDb { } } -impl StorageInspect for MockDb { +impl StorageInspect for MockDb { type Error = KvStoreError; fn get(&self, key: &DaBlockHeight) -> Result>, Self::Error> { @@ -209,7 +209,7 @@ impl StorageInspect for MockDb { } } -impl StorageMutate for MockDb { +impl StorageMutate for MockDb { fn insert( &mut self, key: &DaBlockHeight, From 7c9d20af0e7d9569a8f694eb2dae2558f3e6022d Mon Sep 17 00:00:00 2001 From: green Date: Wed, 14 Sep 2022 16:51:43 +0100 Subject: [PATCH 7/7] Applied suggestions from teh review. --- fuel-core/src/database/storage.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fuel-core/src/database/storage.rs b/fuel-core/src/database/storage.rs index 2fed9d8e862..7ae49fa1139 100644 --- a/fuel-core/src/database/storage.rs +++ b/fuel-core/src/database/storage.rs @@ -19,7 +19,7 @@ impl Mappable for FuelBlocks { /// Unique identifier of the fuel block. type Key = Bytes32; type SetValue = FuelBlockDb; - type GetValue = FuelBlockDb; + type GetValue = Self::SetValue; } /// The latest UTXO id of the contract. The contract's UTXO represents the unique id of the state. @@ -31,7 +31,7 @@ impl Mappable for ContractsLatestUtxo { type Key = ContractId; /// The latest UTXO id. type SetValue = UtxoId; - type GetValue = UtxoId; + type GetValue = Self::SetValue; } /// Receipts of different hidden internal operations.