Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some improvements during work with the database #976

Merged
merged 6 commits into from
Feb 3, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 56 additions & 14 deletions crates/fuel-core/src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,19 +177,16 @@ impl Database {
}
}

// TODO: Get `K` and `V` by reference to force compilation error for the current
// code(we have many `Copy`).
// https://github.com/FuelLabs/fuel-core/issues/622
fn insert<K: AsRef<[u8]>, V: Serialize, R: DeserializeOwned>(
fn _insert<K: AsRef<[u8]>, V: Serialize, R: DeserializeOwned>(
Voxelot marked this conversation as resolved.
Show resolved Hide resolved
&self,
key: K,
column: Column,
value: V,
value: &V,
) -> DatabaseResult<Option<R>> {
let result = self.data.put(
key.as_ref(),
column,
postcard::to_stdvec(&value).map_err(|_| DatabaseError::Codec)?,
postcard::to_stdvec(value).map_err(|_| DatabaseError::Codec)?,
)?;
if let Some(previous) = result {
Ok(Some(
Expand All @@ -200,7 +197,7 @@ impl Database {
}
}

fn remove<V: DeserializeOwned>(
fn _remove<V: DeserializeOwned>(
&self,
key: &[u8],
column: Column,
Expand All @@ -211,7 +208,7 @@ impl Database {
.transpose()
}

fn get<V: DeserializeOwned>(
fn _get<V: DeserializeOwned>(
&self,
key: &[u8],
column: Column,
Expand All @@ -222,25 +219,70 @@ impl Database {
.transpose()
}

// TODO: Rename to `contains_key` to be the same as `StorageInspect`
// https://github.com/FuelLabs/fuel-core/issues/622
fn exists(&self, key: &[u8], column: Column) -> DatabaseResult<bool> {
fn _contains_key(&self, key: &[u8], column: Column) -> DatabaseResult<bool> {
self.data.exists(key, column)
}

fn iter_all<K, V>(
&self,
column: Column,
prefix: Option<Vec<u8>>,
start: Option<Vec<u8>>,
direction: Option<IterDirection>,
) -> impl Iterator<Item = DatabaseResult<(K, V)>> + '_
where
K: From<Vec<u8>>,
V: DeserializeOwned,
{
self.iter_all_filtered::<K, V, Vec<u8>, Vec<u8>>(column, None, None, direction)
}

fn iter_all_by_prefix<K, V, P>(
&self,
column: Column,
prefix: Option<P>,
direction: Option<IterDirection>,
) -> impl Iterator<Item = DatabaseResult<(K, V)>> + '_
where
K: From<Vec<u8>>,
V: DeserializeOwned,
P: AsRef<[u8]>,
{
self.iter_all_filtered::<K, V, P, [u8; 0]>(column, prefix, None, direction)
}

fn iter_all_by_start<K, V, S>(
&self,
column: Column,
start: Option<S>,
direction: Option<IterDirection>,
) -> impl Iterator<Item = DatabaseResult<(K, V)>> + '_
where
K: From<Vec<u8>>,
V: DeserializeOwned,
S: AsRef<[u8]>,
{
self.iter_all_filtered::<K, V, [u8; 0], S>(column, None, start, direction)
}

fn iter_all_filtered<K, V, P, S>(
&self,
column: Column,
prefix: Option<P>,
start: Option<S>,
direction: Option<IterDirection>,
) -> impl Iterator<Item = DatabaseResult<(K, V)>> + '_
where
K: From<Vec<u8>>,
V: DeserializeOwned,
P: AsRef<[u8]>,
S: AsRef<[u8]>,
{
self.data
.iter_all(column, prefix, start, direction.unwrap_or_default())
.iter_all(
column,
prefix.as_ref().map(|p| p.as_ref()),
start.as_ref().map(|s| s.as_ref()),
direction.unwrap_or_default(),
)
.map(|val| {
val.and_then(|(key, value)| {
let key = K::from(key);
Expand Down
14 changes: 7 additions & 7 deletions crates/fuel-core/src/database/balances.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ impl StorageInspect<ContractsAssets> for Database {
&self,
key: &<ContractsAssets as Mappable>::Key,
) -> Result<Option<Cow<<ContractsAssets as Mappable>::OwnedValue>>, Self::Error> {
self.get(key.as_ref(), Column::ContractsAssets)
self._get(key.as_ref(), Column::ContractsAssets)
.map_err(Into::into)
}

fn contains_key(
&self,
key: &<ContractsAssets as Mappable>::Key,
) -> Result<bool, Self::Error> {
self.exists(key.as_ref(), Column::ContractsAssets)
self._contains_key(key.as_ref(), Column::ContractsAssets)
.map_err(Into::into)
}
}
Expand All @@ -48,25 +48,25 @@ impl StorageMutate<ContractsAssets> for Database {
key: &<ContractsAssets as Mappable>::Key,
value: &<ContractsAssets as Mappable>::Value,
) -> Result<Option<<ContractsAssets as Mappable>::OwnedValue>, Self::Error> {
Database::insert(self, key.as_ref(), Column::ContractsAssets, *value)
self._insert(key.as_ref(), Column::ContractsAssets, value)
.map_err(Into::into)
}

fn remove(
&mut self,
key: &<ContractsAssets as Mappable>::Key,
) -> Result<Option<<ContractsAssets as Mappable>::OwnedValue>, Self::Error> {
Database::remove(self, key.as_ref(), Column::ContractsAssets).map_err(Into::into)
self._remove(key.as_ref(), Column::ContractsAssets)
.map_err(Into::into)
}
}

impl MerkleRootStorage<ContractId, ContractsAssets> for Database {
fn root(&self, parent: &ContractId) -> Result<MerkleRoot, Self::Error> {
let items: Vec<_> = Database::iter_all::<Vec<u8>, Word>(
let items: Vec<(Vec<u8>, Word)> = Database::iter_all_by_prefix(
self,
Column::ContractsAssets,
Some(parent.as_ref().to_vec()),
None,
Some(parent),
Some(IterDirection::Forward),
)
.try_collect()?;
Expand Down
23 changes: 9 additions & 14 deletions crates/fuel-core/src/database/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,13 @@ impl StorageInspect<FuelBlocks> for Database {
type Error = StorageError;

fn get(&self, key: &BlockId) -> Result<Option<Cow<CompressedBlock>>, Self::Error> {
Database::get(self, key.as_slice(), Column::FuelBlocks).map_err(Into::into)
self._get(key.as_slice(), Column::FuelBlocks)
.map_err(Into::into)
}

fn contains_key(&self, key: &BlockId) -> Result<bool, Self::Error> {
Database::exists(self, key.as_slice(), Column::FuelBlocks).map_err(Into::into)
self._contains_key(key.as_slice(), Column::FuelBlocks)
.map_err(Into::into)
}
}

Expand All @@ -72,7 +74,7 @@ impl StorageMutate<FuelBlocks> for Database {
key: &BlockId,
value: &CompressedBlock,
) -> Result<Option<CompressedBlock>, Self::Error> {
let prev = Database::insert(self, key.as_slice(), Column::FuelBlocks, value)?;
let prev = self._insert(key.as_slice(), Column::FuelBlocks, value)?;

let height = value.header().height();
self.storage::<FuelBlockSecondaryKeyBlockHeights>()
Expand All @@ -82,8 +84,6 @@ impl StorageMutate<FuelBlocks> for Database {
let prev_metadata = self
.iter_all::<Vec<u8>, DenseMerkleMetadata>(
Column::FuelBlockMerkleMetadata,
None,
None,
Some(IterDirection::Reverse),
)
.next()
Expand All @@ -110,7 +110,7 @@ impl StorageMutate<FuelBlocks> for Database {

fn remove(&mut self, key: &BlockId) -> Result<Option<CompressedBlock>, Self::Error> {
let prev: Option<CompressedBlock> =
Database::remove(self, key.as_slice(), Column::FuelBlocks)?;
self._remove(key.as_slice(), Column::FuelBlocks)?;

if let Some(block) = &prev {
let height = block.header().height();
Expand Down Expand Up @@ -153,7 +153,7 @@ impl Database {
}

pub fn get_block_id(&self, height: &BlockHeight) -> StorageResult<Option<BlockId>> {
Database::get(
Database::_get(
self,
height.database_key().as_ref(),
Column::FuelBlockSecondaryKeyBlockHeights,
Expand All @@ -166,10 +166,9 @@ impl Database {
start: Option<BlockHeight>,
direction: IterDirection,
) -> impl Iterator<Item = DatabaseResult<(BlockHeight, BlockId)>> + '_ {
let start = start.map(|b| b.to_bytes().to_vec());
self.iter_all::<Vec<u8>, BlockId>(
let start = start.map(|b| b.to_bytes());
self.iter_all_by_start::<Vec<u8>, BlockId, _>(
Column::FuelBlockSecondaryKeyBlockHeights,
None,
start,
Some(direction),
)
Expand All @@ -187,8 +186,6 @@ impl Database {
pub fn ids_of_genesis_block(&self) -> DatabaseResult<(BlockHeight, BlockId)> {
self.iter_all(
Column::FuelBlockSecondaryKeyBlockHeights,
None,
None,
Some(IterDirection::Forward),
)
.next()
Expand All @@ -204,8 +201,6 @@ impl Database {
let ids = self
.iter_all::<Vec<u8>, BlockId>(
Column::FuelBlockSecondaryKeyBlockHeights,
None,
None,
Some(IterDirection::Reverse),
)
.next()
Expand Down
2 changes: 1 addition & 1 deletion crates/fuel-core/src/database/code_root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ mod tests {
.unwrap();

assert!(!database
.exists(contract_id.as_ref(), Column::ContractsInfo)
._contains_key(contract_id.as_ref(), Column::ContractsInfo)
.unwrap());
}

Expand Down
54 changes: 27 additions & 27 deletions crates/fuel-core/src/database/coin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use fuel_core_storage::{
StorageInspect,
StorageMutate,
};
use fuel_core_txpool::types::TxId;
use fuel_core_types::{
entities::coin::{
CoinStatus,
Expand All @@ -27,34 +28,35 @@ use fuel_core_types::{
};
use std::borrow::Cow;

fn owner_coin_id_key(owner: &Address, coin_id: &UtxoId) -> Vec<u8> {
owner
.as_ref()
.iter()
.chain(utxo_id_to_bytes(coin_id).iter())
.copied()
.collect()
// TODO: Reuse `fuel_vm::storage::double_key` macro.
fn owner_coin_id_key(
owner: &Address,
coin_id: &UtxoId,
) -> [u8; Address::LEN + TxId::LEN + 1] {
let mut default = [0u8; Address::LEN + TxId::LEN + 1];
default[0..Address::LEN].copy_from_slice(owner.as_ref());
default[Address::LEN..].copy_from_slice(utxo_id_to_bytes(coin_id).as_ref());
default
}

// 32 Bytes for Tx_id + 1 byte for output_index
const SIZE_OF_UTXO_ID: usize = 264;

fn utxo_id_to_bytes(utxo_id: &UtxoId) -> Vec<u8> {
let mut out = Vec::with_capacity(SIZE_OF_UTXO_ID);
out.extend(utxo_id.tx_id().as_ref().iter());
out.push(utxo_id.output_index());
out
fn utxo_id_to_bytes(utxo_id: &UtxoId) -> [u8; TxId::LEN + 1] {
let mut default = [0; TxId::LEN + 1];
default[0..TxId::LEN].copy_from_slice(utxo_id.tx_id().as_ref());
default[TxId::LEN] = utxo_id.output_index();
default
}

impl StorageInspect<Coins> for Database {
type Error = StorageError;

fn get(&self, key: &UtxoId) -> Result<Option<Cow<CompressedCoin>>, Self::Error> {
Database::get(self, &utxo_id_to_bytes(key), Column::Coins).map_err(Into::into)
self._get(&utxo_id_to_bytes(key), Column::Coins)
.map_err(Into::into)
}

fn contains_key(&self, key: &UtxoId) -> Result<bool, Self::Error> {
Database::exists(self, &utxo_id_to_bytes(key), Column::Coins).map_err(Into::into)
self._contains_key(&utxo_id_to_bytes(key), Column::Coins)
.map_err(Into::into)
}
}

Expand All @@ -64,24 +66,22 @@ impl StorageMutate<Coins> for Database {
key: &UtxoId,
value: &CompressedCoin,
) -> Result<Option<CompressedCoin>, Self::Error> {
let coin_by_owner: Vec<u8> = owner_coin_id_key(&value.owner, key);
let coin_by_owner = owner_coin_id_key(&value.owner, key);
// insert primary record
let insert = Database::insert(self, utxo_id_to_bytes(key), Column::Coins, value)?;
let insert = self._insert(utxo_id_to_bytes(key), Column::Coins, value)?;
// insert secondary index by owner
let _: Option<bool> =
Database::insert(self, coin_by_owner, Column::OwnedCoins, true)?;
let _: Option<bool> = self._insert(coin_by_owner, Column::OwnedCoins, &true)?;
Ok(insert)
}

fn remove(&mut self, key: &UtxoId) -> Result<Option<CompressedCoin>, Self::Error> {
let coin: Option<CompressedCoin> =
Database::remove(self, &utxo_id_to_bytes(key), Column::Coins)?;
self._remove(&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<bool> =
Database::remove(self, key.as_slice(), Column::OwnedCoins)?;
let _: Option<bool> = self._remove(key.as_slice(), Column::OwnedCoins)?;
}

Ok(coin)
Expand All @@ -95,9 +95,9 @@ impl Database {
start_coin: Option<UtxoId>,
direction: Option<IterDirection>,
) -> impl Iterator<Item = DatabaseResult<UtxoId>> + '_ {
self.iter_all::<Vec<u8>, bool>(
self.iter_all_filtered::<Vec<u8>, bool, _, _>(
Column::OwnedCoins,
Some(owner.as_ref().to_vec()),
Some(*owner),
start_coin.map(|b| owner_coin_id_key(owner, &b)),
direction,
)
Expand All @@ -114,7 +114,7 @@ impl Database {

pub fn get_coin_config(&self) -> DatabaseResult<Option<Vec<CoinConfig>>> {
let configs = self
.iter_all::<Vec<u8>, CompressedCoin>(Column::Coins, None, None, None)
.iter_all::<Vec<u8>, CompressedCoin>(Column::Coins, None)
.filter_map(|coin| {
// Return only unspent coins
if let Ok(coin) = coin {
Expand Down
Loading