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

Use fresh ReadView for mutate queries #1990

Merged
merged 10 commits into from
Jun 26, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- [#1948](https://github.com/FuelLabs/fuel-core/pull/1948): Add new `AlgorithmV1` and `AlgorithmUpdaterV1` for the gas price. Include tools for analysis

### Changed
- [#1990](https://github.com/FuelLabs/fuel-core/pull/1990): Use latest view for mutate GraphQL queries after modification of the node.

#### Breaking
- [#1989](https://github.com/FuelLabs/fuel-core/pull/1989): Extract `HistoricalView` trait from the `AtomicView`.
Expand Down
1 change: 1 addition & 0 deletions crates/fuel-core/src/graphql_api/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ impl ReadDatabase {
}
}

#[derive(Clone)]
pub struct ReadView {
genesis_height: BlockHeight,
on_chain: OnChainView,
Expand Down
28 changes: 28 additions & 0 deletions crates/fuel-core/src/schema.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
use crate::fuel_core_graphql_api::{
api_service::ReadDatabase,
database::ReadView,
};
use anyhow::anyhow;
use async_graphql::{
connection::{
Expand All @@ -7,6 +11,8 @@ use async_graphql::{
Edge,
EmptyFields,
},
parser::types::OperationType,
Context,
MergedObject,
MergedSubscription,
OutputType,
Expand All @@ -18,6 +24,7 @@ use fuel_core_storage::{
Result as StorageResult,
};
use itertools::Itertools;
use std::borrow::Cow;

pub mod balance;
pub mod block;
Expand Down Expand Up @@ -196,3 +203,24 @@ where
)
.await
}

pub trait ReadViewProvider {
/// Returns the read view for the current operation.
fn read_view(&self) -> StorageResult<Cow<ReadView>>;
}

impl<'a> ReadViewProvider for Context<'a> {
fn read_view(&self) -> StorageResult<Cow<'a, ReadView>> {
let operation_type = self.query_env.operation.node.ty;

// Sometimes, during mutable queries the resolvers
// need access to an updated view of the database.
if operation_type == OperationType::Mutation {
let database: &ReadDatabase = self.data_unchecked();
database.view().map(Cow::Owned)
} else {
let read_view: &ReadView = self.data_unchecked();
Ok(Cow::Borrowed(read_view))
}
}
}
20 changes: 10 additions & 10 deletions crates/fuel-core/src/schema/balance.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use crate::{
fuel_core_graphql_api::{
api_service::ConsensusProvider,
database::ReadView,
},
fuel_core_graphql_api::api_service::ConsensusProvider,
query::BalanceQueryData,
schema::scalars::{
Address,
AssetId,
U64,
schema::{
scalars::{
Address,
AssetId,
U64,
},
ReadViewProvider,
},
};
use anyhow::anyhow;
Expand Down Expand Up @@ -56,7 +56,7 @@ impl BalanceQuery {
#[graphql(desc = "address of the owner")] owner: Address,
#[graphql(desc = "asset_id of the coin")] asset_id: AssetId,
) -> async_graphql::Result<Balance> {
let query: &ReadView = ctx.data_unchecked();
let query = ctx.read_view()?;
let base_asset_id = *ctx
.data_unchecked::<ConsensusProvider>()
.latest_consensus_params()
Expand All @@ -82,7 +82,7 @@ impl BalanceQuery {
if before.is_some() || after.is_some() {
return Err(anyhow!("pagination is not yet supported").into())
}
let query: &ReadView = ctx.data_unchecked();
let query = ctx.read_view()?;
crate::schema::query_pagination(after, before, first, last, |_, direction| {
let owner = filter.owner.into();
let base_asset_id = *ctx
Expand Down
25 changes: 17 additions & 8 deletions crates/fuel-core/src/schema/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use crate::{
U64,
},
tx::types::Transaction,
ReadViewProvider,
},
};
use anyhow::anyhow;
Expand Down Expand Up @@ -116,7 +117,7 @@ impl Block {
}

async fn consensus(&self, ctx: &Context<'_>) -> async_graphql::Result<Consensus> {
let query: &ReadView = ctx.data_unchecked();
let query = ctx.read_view()?;
let height = self.0.header().height();
Ok(query.consensus(height)?.try_into()?)
}
Expand All @@ -125,7 +126,7 @@ impl Block {
&self,
ctx: &Context<'_>,
) -> async_graphql::Result<Vec<Transaction>> {
let query: &ReadView = ctx.data_unchecked();
let query = ctx.read_view()?;
self.0
.transactions()
.iter()
Expand Down Expand Up @@ -237,7 +238,7 @@ impl BlockQuery {
#[graphql(desc = "ID of the block")] id: Option<BlockId>,
#[graphql(desc = "Height of the block")] height: Option<U32>,
) -> async_graphql::Result<Option<Block>> {
let query: &ReadView = ctx.data_unchecked();
let query = ctx.read_view()?;
let height = match (id, height) {
(Some(_), Some(_)) => {
return Err(async_graphql::Error::new(
Expand Down Expand Up @@ -267,9 +268,13 @@ impl BlockQuery {
last: Option<i32>,
before: Option<String>,
) -> async_graphql::Result<Connection<U32, Block, EmptyFields, EmptyFields>> {
let query: &ReadView = ctx.data_unchecked();
let query = ctx.read_view()?;
crate::schema::query_pagination(after, before, first, last, |start, direction| {
Ok(blocks_query(query, start.map(Into::into), direction))
Ok(blocks_query(
query.as_ref(),
start.map(Into::into),
direction,
))
})
.await
}
Expand Down Expand Up @@ -300,9 +305,13 @@ impl HeaderQuery {
last: Option<i32>,
before: Option<String>,
) -> async_graphql::Result<Connection<U32, Header, EmptyFields, EmptyFields>> {
let query: &ReadView = ctx.data_unchecked();
let query = ctx.read_view()?;
crate::schema::query_pagination(after, before, first, last, |start, direction| {
Ok(blocks_query(query, start.map(Into::into), direction))
Ok(blocks_query(
query.as_ref(),
start.map(Into::into),
direction,
))
})
.await
}
Expand Down Expand Up @@ -339,7 +348,7 @@ impl BlockMutation {
start_timestamp: Option<Tai64Timestamp>,
blocks_to_produce: U32,
) -> async_graphql::Result<U32> {
let query: &ReadView = ctx.data_unchecked();
let query = ctx.read_view()?;
let consensus_module = ctx.data_unchecked::<ConsensusModule>();
let config = ctx.data_unchecked::<GraphQLConfig>().clone();

Expand Down
18 changes: 7 additions & 11 deletions crates/fuel-core/src/schema/chain.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use crate::{
fuel_core_graphql_api::{
api_service::ConsensusProvider,
database::ReadView,
},
fuel_core_graphql_api::api_service::ConsensusProvider,
graphql_api::Config,
query::{
BlockQueryData,
Expand All @@ -17,6 +14,7 @@ use crate::{
U32,
U64,
},
ReadViewProvider,
},
};
use async_graphql::{
Expand Down Expand Up @@ -816,20 +814,18 @@ impl ChainInfo {
}

async fn latest_block(&self, ctx: &Context<'_>) -> async_graphql::Result<Block> {
let query: &ReadView = ctx.data_unchecked();
let query = ctx.read_view()?;

let latest_block = query.latest_block()?.into();
Ok(latest_block)
}

async fn da_height(&self, ctx: &Context<'_>) -> U64 {
let query: &ReadView = ctx.data_unchecked();

let height = query
.da_height()
.expect("The blockchain always should have genesis block");
let Ok(query) = ctx.read_view() else {
return 0.into();
};
Copy link
Member

Choose a reason for hiding this comment

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

Is this change of behavior intentional? Is returning zero correct?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

If I change the output type to Result, it will change the schema, and it will be a breaking change.

Copy link
Member

Choose a reason for hiding this comment

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

My question is: should we rather panic or return zero? But all things considered I think zero is fine here.


height.0.into()
query.da_height().unwrap_or_default().0.into()
}

async fn consensus_parameters(
Expand Down
32 changes: 16 additions & 16 deletions crates/fuel-core/src/schema/coins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,23 @@ use crate::{
random_improve,
SpendQuery,
},
fuel_core_graphql_api::{
database::ReadView,
IntoApiResult,
},
fuel_core_graphql_api::IntoApiResult,
graphql_api::api_service::ConsensusProvider,
query::{
asset_query::AssetSpendTarget,
CoinQueryData,
},
schema::scalars::{
Address,
AssetId,
Nonce,
UtxoId,
U16,
U32,
U64,
schema::{
scalars::{
Address,
AssetId,
Nonce,
UtxoId,
U16,
U32,
U64,
},
ReadViewProvider,
},
};
use async_graphql::{
Expand Down Expand Up @@ -152,7 +152,7 @@ impl CoinQuery {
ctx: &Context<'_>,
#[graphql(desc = "The ID of the coin")] utxo_id: UtxoId,
) -> async_graphql::Result<Option<Coin>> {
let query: &ReadView = ctx.data_unchecked();
let query = ctx.read_view()?;
query.coin(utxo_id.0).into_api_result()
}

Expand All @@ -166,7 +166,7 @@ impl CoinQuery {
last: Option<i32>,
before: Option<String>,
) -> async_graphql::Result<Connection<UtxoId, Coin, EmptyFields, EmptyFields>> {
let query: &ReadView = ctx.data_unchecked();
let query = ctx.read_view()?;
crate::schema::query_pagination(after, before, first, last, |start, direction| {
let owner: fuel_tx::Address = filter.owner.into();
let coins = query
Expand Down Expand Up @@ -242,9 +242,9 @@ impl CoinQuery {
let spend_query =
SpendQuery::new(owner, &query_per_asset, excluded_ids, *base_asset_id)?;

let query: &ReadView = ctx.data_unchecked();
let query = ctx.read_view()?;

let coins = random_improve(query, &spend_query)?
let coins = random_improve(query.as_ref(), &spend_query)?
.into_iter()
.map(|coins| {
coins
Expand Down
30 changes: 15 additions & 15 deletions crates/fuel-core/src/schema/contract.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
use crate::{
fuel_core_graphql_api::{
database::ReadView,
IntoApiResult,
},
fuel_core_graphql_api::IntoApiResult,
query::ContractQueryData,
schema::scalars::{
AssetId,
ContractId,
HexString,
Salt,
U64,
schema::{
scalars::{
AssetId,
ContractId,
HexString,
Salt,
U64,
},
ReadViewProvider,
},
};
use async_graphql::{
Expand Down Expand Up @@ -41,15 +41,15 @@ impl Contract {
}

async fn bytecode(&self, ctx: &Context<'_>) -> async_graphql::Result<HexString> {
let query: &ReadView = ctx.data_unchecked();
let query = ctx.read_view()?;
query
.contract_bytecode(self.0)
.map(HexString)
.map_err(Into::into)
}

async fn salt(&self, ctx: &Context<'_>) -> async_graphql::Result<Salt> {
let query: &ReadView = ctx.data_unchecked();
let query = ctx.read_view()?;
query
.contract_salt(self.0)
.map(Into::into)
Expand All @@ -67,7 +67,7 @@ impl ContractQuery {
ctx: &Context<'_>,
#[graphql(desc = "ID of the Contract")] id: ContractId,
) -> async_graphql::Result<Option<Contract>> {
let query: &ReadView = ctx.data_unchecked();
let query = ctx.read_view()?;
query.contract_id(id.0).into_api_result()
}
}
Expand Down Expand Up @@ -108,7 +108,7 @@ impl ContractBalanceQuery {
) -> async_graphql::Result<ContractBalance> {
let contract_id = contract.into();
let asset_id = asset.into();
let query: &ReadView = ctx.data_unchecked();
let query = ctx.read_view()?;
query
.contract_balance(contract_id, asset_id)
.into_api_result()
Expand All @@ -135,7 +135,7 @@ impl ContractBalanceQuery {
) -> async_graphql::Result<
Connection<AssetId, ContractBalance, EmptyFields, EmptyFields>,
> {
let query: &ReadView = ctx.data_unchecked();
let query = ctx.read_view()?;

crate::schema::query_pagination(after, before, first, last, |start, direction| {
let balances = query
Expand Down
6 changes: 3 additions & 3 deletions crates/fuel-core/src/schema/gas_price.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ use super::scalars::{
U64,
};
use crate::{
fuel_core_graphql_api::database::ReadView,
graphql_api::api_service::GasPriceProvider,
query::{
BlockQueryData,
SimpleTransactionData,
},
schema::ReadViewProvider,
};
use async_graphql::{
Context,
Expand Down Expand Up @@ -47,7 +47,7 @@ impl LatestGasPriceQuery {
&self,
ctx: &Context<'_>,
) -> async_graphql::Result<LatestGasPrice> {
let query: &ReadView = ctx.data_unchecked();
let query = ctx.read_view()?;

let latest_block: Block<_> = query.latest_block()?;
let block_height: u32 = (*latest_block.header().height()).into();
Expand Down Expand Up @@ -88,7 +88,7 @@ impl EstimateGasPriceQuery {
)]
block_horizon: Option<U32>,
) -> async_graphql::Result<EstimateGasPrice> {
let query: &ReadView = ctx.data_unchecked();
let query = ctx.read_view()?;

let latest_block_height: u32 = query.latest_block_height()?.into();
let target_block = block_horizon
Expand Down
Loading
Loading