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
10 changes: 5 additions & 5 deletions crates/fuel-core/src/database.rs
Original file line number Diff line number Diff line change
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,7 +339,7 @@ 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)
}
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)
}
}
108 changes: 60 additions & 48 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.latest_block_ids()?;
// 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()?;
let block_entry = self.latest_block_ids()?;
match block_entry {
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 genesis_block_ids(&self) -> DatabaseResult<(BlockHeight, BlockId)> {
ControlCplusControlV marked this conversation as resolved.
Show resolved Hide resolved
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 latest_block_ids(&self) -> DatabaseResult<Option<(BlockHeight, BlockId)>> {
ControlCplusControlV marked this conversation as resolved.
Show resolved Hide resolved
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
41 changes: 21 additions & 20 deletions crates/fuel-core/src/database/sealed_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,53 +14,54 @@ use fuel_core_storage::{
StorageInspect,
StorageMutate,
};
use fuel_core_types::{
blockchain::{
consensus::{
Consensus,
Genesis,
},
primitives::BlockHeight,
SealedBlock,
SealedBlockHeader,
use fuel_core_types::blockchain::{
consensus::{
Consensus,
Genesis,
},
fuel_tx::Bytes32,
primitives::{
BlockHeight,
BlockId,
},
SealedBlock,
SealedBlockHeader,
};
use std::borrow::Cow;

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

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

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

impl StorageMutate<SealedBlockConsensus> for Database {
fn insert(
&mut self,
key: &Bytes32,
key: &BlockId,
value: &Consensus,
) -> Result<Option<Consensus>, Self::Error> {
Database::insert(self, key.as_ref(), Column::FuelBlockConsensus, value)
Database::insert(self, key.as_slice(), Column::FuelBlockConsensus, value)
.map_err(Into::into)
}

fn remove(&mut self, key: &Bytes32) -> Result<Option<Consensus>, Self::Error> {
Database::remove(self, key.as_ref(), Column::FuelBlockConsensus)
fn remove(&mut self, key: &BlockId) -> Result<Option<Consensus>, Self::Error> {
Database::remove(self, key.as_slice(), Column::FuelBlockConsensus)
.map_err(Into::into)
}
}

impl Database {
pub fn get_sealed_block_by_id(
&self,
block_id: &Bytes32,
block_id: &BlockId,
) -> StorageResult<Option<SealedBlock>> {
// combine the block and consensus metadata into a sealed fuel block type

Expand Down Expand Up @@ -105,7 +106,7 @@ impl Database {

pub fn get_sealed_block_header(
&self,
block_id: &Bytes32,
block_id: &BlockId,
) -> StorageResult<Option<SealedBlockHeader>> {
let header = self.storage::<FuelBlocks>().get(block_id)?;
let consensus = self.storage::<SealedBlockConsensus>().get(block_id)?;
Expand Down
4 changes: 2 additions & 2 deletions crates/fuel-core/src/database/transactional.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{
state::in_memory::transaction::MemoryTransactionView,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should the name of this file/module be renamed now that we no longer use Transactional?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will update it in a separate PR to not lose history

};
use fuel_core_storage::{
transactional::Transactional,
transactional::Transaction,
Result as StorageResult,
};
use std::{
Expand Down Expand Up @@ -55,7 +55,7 @@ impl Default for DatabaseTransaction {
}
}

impl Transactional<Database> for DatabaseTransaction {
impl Transaction<Database> for DatabaseTransaction {
fn commit(&mut self) -> StorageResult<()> {
// TODO: should commit be fallible if this api is meant to be atomic?
Ok(self.changes.commit()?)
Expand Down
3 changes: 2 additions & 1 deletion crates/fuel-core/src/database/vm_database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ impl InterpreterStorage for VmDatabase {
return Err(anyhow!("block height too high for timestamp").into())
}
height if height == self.current_block_height => self.current_timestamp,
height => self.database.block_time(height)?,
height => self.database.block_time(height.into())?,
};
Ok(timestamp.0)
}
Expand All @@ -155,6 +155,7 @@ impl InterpreterStorage for VmDatabase {
self.database
.get_block_id(block_height.into())?
.ok_or(not_found!("BlockId"))
.map(Into::into)
ControlCplusControlV marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down
4 changes: 2 additions & 2 deletions crates/fuel-core/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use fuel_core_storage::{
},
transactional::{
StorageTransaction,
Transactional,
Transaction as StorageTransactionTrait,
},
StorageAsMut,
StorageAsRef,
Expand Down Expand Up @@ -274,7 +274,7 @@ impl Executor {
block_db_transaction
.deref_mut()
.storage::<FuelBlocks>()
.insert(&finalized_block_id.into(), &result.block.compress())?;
.insert(&finalized_block_id, &result.block.compress())?;

// Get the complete fuel block.
Ok(UncommittedResult::new(
Expand Down
1 change: 1 addition & 0 deletions crates/fuel-core/src/graphql_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use fuel_core_types::{
};
use std::net::SocketAddr;

pub mod ports;
pub mod service;

#[derive(Clone, Debug)]
Expand Down
Loading