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

graphql-api ports for database queries #890

Merged
merged 9 commits into from
Jan 11, 2023
Merged
4 changes: 2 additions & 2 deletions crates/chain-config/src/config/coin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
use fuel_core_storage::MerkleRoot;
use fuel_core_types::{
blockchain::primitives::BlockHeight,
entities::coin::Coin,
entities::coin::CompressedCoin,
fuel_crypto::Hasher,
fuel_types::{
Address,
Expand Down Expand Up @@ -52,7 +52,7 @@ pub struct CoinConfig {
pub asset_id: AssetId,
}

impl GenesisCommitment for Coin {
impl GenesisCommitment for CompressedCoin {
fn root(&mut self) -> anyhow::Result<MerkleRoot> {
let coin_hash = *Hasher::default()
.chain(self.owner)
Expand Down
2 changes: 1 addition & 1 deletion crates/client/assets/schema.sdl
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,7 @@ enum ReceiptType {
}

"""
The schema analog of the [`crate::database::utils::Resource`].
The schema analog of the [`resource::Resource`].
"""
union Resource = Coin | Message

Expand Down
20 changes: 10 additions & 10 deletions crates/fuel-core/src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ use fuel_core_storage::tables::{
use fuel_core_txpool::ports::TxPoolDb;
use fuel_core_types::{
entities::{
coin::Coin,
coin::CompressedCoin,
message::Message,
},
fuel_tx::UtxoId,
Expand Down Expand Up @@ -98,9 +98,9 @@ mod state;

pub mod balances;
pub mod metadata;
pub mod resource;
pub mod transaction;
// TODO: Rename in a separate PR into `transaction`
pub mod transactional;
pub mod transactions;
pub mod vm_database;

/// Database tables column ids.
Expand Down Expand Up @@ -135,7 +135,7 @@ pub enum Column {
Receipts = 11,
/// See [`FuelBlocks`](fuel_core_storage::tables::FuelBlocks)
FuelBlocks = 12,
/// Maps fuel block id to fuel block hash
/// Maps fuel block height to fuel block id
FuelBlockIds = 13,
/// See [`Messages`](fuel_core_storage::tables::Messages)
Messages = 14,
Expand Down Expand Up @@ -330,7 +330,7 @@ impl Default for Database {

impl BlockDb for Database {
fn block_height(&self) -> anyhow::Result<BlockHeight> {
Ok(self.get_block_height()?.unwrap_or_default())
Ok(self.latest_height()?.unwrap_or_default())
}

fn seal_block(
Expand All @@ -339,14 +339,14 @@ impl BlockDb for Database {
consensus: Consensus,
) -> anyhow::Result<()> {
self.storage::<SealedBlockConsensus>()
.insert(&block_id.into(), &consensus)
.insert(&block_id, &consensus)
.map(|_| ())
.map_err(Into::into)
}
}

impl TxPoolDb for Database {
fn utxo(&self, utxo_id: &UtxoId) -> StorageResult<Option<Coin>> {
fn utxo(&self, utxo_id: &UtxoId) -> StorageResult<Option<CompressedCoin>> {
self.storage::<Coins>()
.get(utxo_id)
.map(|t| t.map(|t| t.as_ref().clone()))
Expand All @@ -363,7 +363,7 @@ impl TxPoolDb for Database {
}

fn current_block_height(&self) -> StorageResult<BlockHeight> {
self.get_block_height()
self.latest_height()
.map(|h| h.unwrap_or_default())
.map_err(Into::into)
}
Expand All @@ -381,7 +381,7 @@ impl BlockProducerDatabase for Database {
}

fn current_block_height(&self) -> StorageResult<BlockHeight> {
self.get_block_height()
self.latest_height()
.map(|h| h.unwrap_or_default())
.map_err(Into::into)
}
Expand All @@ -403,6 +403,6 @@ impl ChainConfigDb for Database {
}

fn get_block_height(&self) -> StorageResult<Option<BlockHeight>> {
Self::get_block_height(self).map_err(Into::into)
Self::latest_height(self).map_err(Into::into)
}
}
110 changes: 61 additions & 49 deletions crates/fuel-core/src/database/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ use fuel_core_types::{
Block,
CompressedBlock,
},
primitives::BlockHeight,
primitives::{
BlockHeight,
BlockId,
},
},
fuel_tx::Bytes32,
tai64::Tai64,
Expand All @@ -42,19 +45,19 @@ use std::{
impl StorageInspect<FuelBlocks> for Database {
type Error = StorageError;

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

fn contains_key(&self, key: &Bytes32) -> Result<bool, Self::Error> {
Database::exists(self, key.as_ref(), 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)
}
}

impl StorageMutate<FuelBlocks> for Database {
fn insert(
&mut self,
key: &Bytes32,
key: &BlockId,
value: &CompressedBlock,
) -> Result<Option<CompressedBlock>, Self::Error> {
let _: Option<BlockHeight> = Database::insert(
Expand All @@ -63,13 +66,13 @@ impl StorageMutate<FuelBlocks> for Database {
Column::FuelBlockIds,
*key,
)?;
Database::insert(self, key.as_ref(), Column::FuelBlocks, value)
Database::insert(self, key.as_slice(), Column::FuelBlocks, value)
.map_err(Into::into)
}

fn remove(&mut self, key: &Bytes32) -> Result<Option<CompressedBlock>, Self::Error> {
fn remove(&mut self, key: &BlockId) -> Result<Option<CompressedBlock>, Self::Error> {
let block: Option<CompressedBlock> =
Database::remove(self, key.as_ref(), Column::FuelBlocks)?;
Database::remove(self, key.as_slice(), Column::FuelBlocks)?;
if let Some(block) = &block {
let _: Option<Bytes32> = Database::remove(
self,
Expand All @@ -82,63 +85,64 @@ impl StorageMutate<FuelBlocks> for Database {
}

impl Database {
pub fn get_block_height(&self) -> DatabaseResult<Option<BlockHeight>> {
let block_entry = self.latest_block()?;
// get block height from most recently indexed block
let mut id = block_entry.map(|(height, _)| {
// safety: we know that all block heights are stored with the correct amount of bytes
let bytes = <[u8; 4]>::try_from(height.as_slice()).unwrap();
u32::from_be_bytes(bytes).into()
});
pub fn latest_height(&self) -> DatabaseResult<Option<BlockHeight>> {
let id = self.ids_of_latest_block()?;
// if no blocks, check if chain was configured with a base height
if id.is_none() {
id = self.get_starting_chain_height()?;
}
let id = match id {
Some((id, _)) => Some(id),
None => self.get_starting_chain_height()?,
};

Ok(id)
}

/// Get the current block at the head of the chain.
pub fn get_current_block(&self) -> StorageResult<Option<Cow<CompressedBlock>>> {
let block_entry = self.latest_block()?;
match block_entry {
let block_ids = self.ids_of_latest_block()?;
match block_ids {
Some((_, id)) => Ok(StorageAsRef::storage::<FuelBlocks>(self).get(&id)?),
None => Ok(None),
}
}

pub fn block_time(&self, height: u32) -> StorageResult<Tai64> {
let id = self.get_block_id(height.into())?.unwrap_or_default();
pub fn block_time(&self, height: BlockHeight) -> StorageResult<Tai64> {
let id = self.get_block_id(height)?.unwrap_or_default();
let block = self
.storage::<FuelBlocks>()
.get(&id)?
.ok_or(not_found!(FuelBlocks))?;
Ok(block.header().time().to_owned())
}

pub fn get_block_id(&self, height: BlockHeight) -> StorageResult<Option<Bytes32>> {
pub fn get_block_id(&self, height: BlockHeight) -> StorageResult<Option<BlockId>> {
Database::get(self, &height.to_bytes()[..], Column::FuelBlockIds)
.map_err(Into::into)
}

pub fn all_block_ids(
&self,
start: Option<BlockHeight>,
direction: Option<IterDirection>,
) -> impl Iterator<Item = DatabaseResult<(BlockHeight, Bytes32)>> + '_ {
direction: IterDirection,
) -> impl Iterator<Item = DatabaseResult<(BlockHeight, BlockId)>> + '_ {
let start = start.map(|b| b.to_bytes().to_vec());
self.iter_all::<Vec<u8>, Bytes32>(Column::FuelBlockIds, None, start, direction)
.map(|res| {
let (height, id) = res?;
Ok((
height
.try_into()
.expect("block height always has correct number of bytes"),
id,
))
})
self.iter_all::<Vec<u8>, BlockId>(
Column::FuelBlockIds,
None,
start,
Some(direction),
)
.map(|res| {
let (height, id) = res?;
Ok((
height
.try_into()
.expect("block height always has correct number of bytes"),
id,
))
})
}

pub fn genesis_block_ids(&self) -> DatabaseResult<(BlockHeight, Bytes32)> {
pub fn ids_of_genesis_block(&self) -> DatabaseResult<(BlockHeight, BlockId)> {
self.iter_all(
Column::FuelBlockIds,
None,
Expand All @@ -147,28 +151,36 @@ impl Database {
)
.next()
.ok_or(DatabaseError::ChainUninitialized)?
.map(|(height, id): (Vec<u8>, Bytes32)| {
.map(|(height, id): (Vec<u8>, BlockId)| {
let bytes = <[u8; 4]>::try_from(height.as_slice())
.expect("all block heights are stored with the correct amount of bytes");
(u32::from_be_bytes(bytes).into(), id)
})
}

fn latest_block(&self) -> DatabaseResult<Option<(Vec<u8>, Bytes32)>> {
self.iter_all(
Column::FuelBlockIds,
None,
None,
Some(IterDirection::Reverse),
)
.next()
.transpose()
pub fn ids_of_latest_block(&self) -> DatabaseResult<Option<(BlockHeight, BlockId)>> {
let ids = self
.iter_all::<Vec<u8>, BlockId>(
Column::FuelBlockIds,
ControlCplusControlV marked this conversation as resolved.
Show resolved Hide resolved
None,
None,
Some(IterDirection::Reverse),
)
.next()
.transpose()?
.map(|(height, block)| {
// safety: we know that all block heights are stored with the correct amount of bytes
let bytes = <[u8; 4]>::try_from(height.as_slice()).unwrap();
(u32::from_be_bytes(bytes).into(), block)
});

Ok(ids)
}

/// Retrieve the full block and all associated transactions
pub(crate) fn get_full_block(
&self,
block_id: &Bytes32,
block_id: &BlockId,
) -> StorageResult<Option<Block>> {
let db_block = self.storage::<FuelBlocks>().get(block_id)?;
if let Some(block) = db_block {
Expand Down
14 changes: 7 additions & 7 deletions crates/fuel-core/src/database/coin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ use fuel_core_storage::{
};
use fuel_core_types::{
entities::coin::{
Coin,
CoinStatus,
CompressedCoin,
},
fuel_tx::{
Address,
Expand Down Expand Up @@ -49,7 +49,7 @@ fn utxo_id_to_bytes(utxo_id: &UtxoId) -> Vec<u8> {
impl StorageInspect<Coins> for Database {
type Error = StorageError;

fn get(&self, key: &UtxoId) -> Result<Option<Cow<Coin>>, Self::Error> {
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)
}

Expand All @@ -62,8 +62,8 @@ impl StorageMutate<Coins> for Database {
fn insert(
&mut self,
key: &UtxoId,
value: &Coin,
) -> Result<Option<Coin>, Self::Error> {
value: &CompressedCoin,
) -> Result<Option<CompressedCoin>, Self::Error> {
let coin_by_owner: Vec<u8> = owner_coin_id_key(&value.owner, key);
// insert primary record
let insert = Database::insert(self, utxo_id_to_bytes(key), Column::Coins, value)?;
Expand All @@ -73,8 +73,8 @@ impl StorageMutate<Coins> for Database {
Ok(insert)
}

fn remove(&mut self, key: &UtxoId) -> Result<Option<Coin>, Self::Error> {
let coin: Option<Coin> =
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)?;

// cleanup secondary index
Expand Down Expand Up @@ -114,7 +114,7 @@ impl Database {

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