Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
cc4e8c2
Introduce separate module for GraphQL extensions
Feb 13, 2025
3b48d47
Revert changes to test structure
Feb 13, 2025
9bd97b7
Add scaffolding for the `current_stf_version` extension
Feb 13, 2025
ac861c4
Add possible way to go with the SFT update notification
Feb 13, 2025
c022ba7
Add `current_consensus_parameters_version` GraphQL extension
Feb 13, 2025
56d4c57
Elaborate on the possible ways to go for STF
Feb 13, 2025
51237b3
Use `latest_consensus_parameters_version()` instead of `latest_consen…
Feb 13, 2025
335b243
Add `current_stf_version` GraphQL extension
Feb 13, 2025
946e315
Update comment
Feb 13, 2025
2616cd7
Update changelog
Feb 13, 2025
da57953
Merge remote-tracking branch 'upstream/master' into rafal/2596_additi…
Feb 14, 2025
2772ba7
Add test checking that proper consensus parameters version is returne…
Feb 14, 2025
3359d61
Add test checking that proper stf version is returned via GraphQL ext…
Feb 14, 2025
d51222f
Clean-up
Feb 14, 2025
5c24c74
Merge remote-tracking branch 'origin/master' into rafal/2596_addition…
Feb 17, 2025
bd610e7
Merge STF and CP extensions into one
Feb 17, 2025
3f3e971
Provide current block height via 'chain state info' extension
Feb 17, 2025
c3c0148
Typos
Feb 17, 2025
ef9c445
Access latest STF and CP version via `FuelClient`
Feb 17, 2025
b861a51
Cache STF version in consensus parameters provider
Feb 18, 2025
0b27037
Move all GraphQL extensions into a single place
Feb 18, 2025
946fc41
Worker service now uses STF provider, not ConsensusParameters provider
Feb 18, 2025
accfae0
Unify `current` vs `latest` naming in the code around grapqhql extens…
Feb 18, 2025
4cd21b4
Merge remote-tracking branch 'origin/master' into rafal/2596_addition…
Feb 20, 2025
bbecdb8
Update changelog according to the new changelog management system
Feb 20, 2025
e0f21bf
Merge remote-tracking branch 'origin/master' into rafal/2596_addition…
Feb 21, 2025
6d1ec52
Move const into the test code
Feb 21, 2025
3f32362
Remove unnecessary comment
Feb 21, 2025
d8ea573
`ConsensusParametersProvider` uses `RwLock` instead of `Mutex`
Feb 21, 2025
69b0da5
Match all variants explicitly
Feb 21, 2025
3aa2d2d
Chain state info is updated in `decode_response` to also be included …
Feb 21, 2025
e03baac
Fix formatting
Feb 21, 2025
932a1c5
Do not add ConsensusParametersProvider to worker service
Feb 21, 2025
ed1dd26
Clean-up
Feb 21, 2025
bfc5f58
Clean-up
Feb 21, 2025
03f9645
Merge remote-tracking branch 'origin/master' into rafal/2596_addition…
Feb 21, 2025
b44cac9
Applied comments from the PR
xgreenx Feb 22, 2025
9c963d5
Merge branch 'master' into rafal/2596_additional_graphql_extensions
rafal-ch Feb 24, 2025
2d682fc
Merge branch 'master' into rafal/2596_additional_graphql_extensions
rafal-ch Feb 24, 2025
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
2 changes: 1 addition & 1 deletion crates/fuel-core/src/graphql_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ use std::{
pub mod api_service;
pub mod da_compression;
pub mod database;
pub(crate) mod extensions;
pub(crate) mod indexation;
pub(crate) mod metrics_extension;
pub mod ports;
pub(crate) mod required_fuel_block_height_extension;
pub mod storage;
pub(crate) mod validation_extension;
pub(crate) mod view_extension;
Expand Down
8 changes: 7 additions & 1 deletion crates/fuel-core/src/graphql_api/api_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ use crate::{
},
graphql_api::{
self,
required_fuel_block_height_extension::RequiredFuelBlockHeightExtension,
extensions::{
current_consensus_parameters_version::CurrentConsensusParametersVersionExtension,
current_stf_version::CurrentStfVersionExtension,
required_fuel_block_height::RequiredFuelBlockHeightExtension,
},
},
schema::{
CoreSchema,
Expand Down Expand Up @@ -287,6 +291,8 @@ where
// `RequiredFuelBlockHeightExtension` uses the view set by the ViewExtension.
// Do not reorder this line before adding the `ViewExtension`.
.extension(RequiredFuelBlockHeightExtension::new())
.extension(CurrentStfVersionExtension::new())
.extension(CurrentConsensusParametersVersionExtension::new())
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think spawning a separate extension for the field it is too overkill=D It decreases performance without any reason

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we can have one extension fully dedicated to return information to the end user. Like STFV, CPV, current block height(we can remove setting of the current height from the RequiredFuelBlockHeightExtension).

In this case we will have one extension that we can use to add any metadata

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The following changes have been made:

  • Both STF and CP extensions have been merged into "chain state info" extension
  • The "chain state info" extension is now also providing data about the current block height

.finish();

let graphql_endpoint = "/v1/graphql";
Expand Down
3 changes: 3 additions & 0 deletions crates/fuel-core/src/graphql_api/extensions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub(crate) mod current_consensus_parameters_version;
pub(crate) mod current_stf_version;
pub(crate) mod required_fuel_block_height;
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use std::sync::Arc;

use crate::graphql_api::api_service::ConsensusProvider;
use async_graphql::{
extensions::{
Extension,
ExtensionContext,
ExtensionFactory,
NextExecute,
},
Response,
Value,
};

const CURRENT_CONSENSUS_PARAMETERS_VERSION: &str = "current_consensus_parameters_version";

/// The extension to attach the current STF version to all responses.
#[derive(Debug, derive_more::Display, derive_more::From)]
pub(crate) struct CurrentConsensusParametersVersionExtension;
impl CurrentConsensusParametersVersionExtension {
pub fn new() -> Self {
Self
}
}

impl ExtensionFactory for CurrentConsensusParametersVersionExtension {
fn create(&self) -> Arc<dyn Extension> {
Arc::new(CurrentConsensusParametersVersionExtension::new())
}
}

#[async_trait::async_trait]
impl Extension for CurrentConsensusParametersVersionExtension {
async fn execute(
&self,
ctx: &ExtensionContext<'_>,
operation_name: Option<&str>,
next: NextExecute<'_>,
) -> Response {
let consensus_parameters_provider = ctx.data_unchecked::<ConsensusProvider>();

let current_consensus_parameters_version =
consensus_parameters_provider.latest_consensus_parameters_version();

let mut response = next.run(ctx, operation_name).await;
response.extensions.insert(
CURRENT_CONSENSUS_PARAMETERS_VERSION.to_string(),
Value::Number(current_consensus_parameters_version.into()),
);
response
}
}
57 changes: 57 additions & 0 deletions crates/fuel-core/src/graphql_api/extensions/current_stf_version.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use std::sync::Arc;

use async_graphql::{
extensions::{
Extension,
ExtensionContext,
ExtensionFactory,
NextExecute,
},
Response,
Value,
};

use crate::graphql_api::database::ReadDatabase;

const CURRENT_STF_VERSION: &str = "current_stf_version";

/// The extension to attach the current STF version to all responses.
#[derive(Debug, derive_more::Display, derive_more::From)]
pub(crate) struct CurrentStfVersionExtension;
impl CurrentStfVersionExtension {
pub fn new() -> Self {
Self
}
}

impl ExtensionFactory for CurrentStfVersionExtension {
fn create(&self) -> Arc<dyn Extension> {
Arc::new(CurrentStfVersionExtension::new())
}
}

#[async_trait::async_trait]
impl Extension for CurrentStfVersionExtension {
async fn execute(
&self,
ctx: &ExtensionContext<'_>,
operation_name: Option<&str>,
next: NextExecute<'_>,
) -> Response {
let db = ctx.data_unchecked::<ReadDatabase>();

let mut response = next.run(ctx, operation_name).await;
if let Ok(view) = db.view() {
if let Ok(latest_block) = view.latest_block() {
let current_stf_version =
latest_block.header().state_transition_bytecode_version();
response.extensions.insert(
CURRENT_STF_VERSION.to_string(),
Value::Number(current_stf_version.into()),
);
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We might prefer reading the current STF version directly from on chain DB table StateTransitionBytecodeVersions similarly to how it's done in BlockProducerDatabase::latest_state_transition_bytecode_version(), but I couldn't figure out how to access this in GraphQL.

Copy link
Collaborator

Choose a reason for hiding this comment

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

We need to have a place where we cache this kind of information. Maybe, we could extend consensus parameters provider to also provide this kind of information, because fetch it from the database it a lot of waste work.

Copy link
Contributor

@acerone85 acerone85 Feb 17, 2025

Choose a reason for hiding this comment

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

If we do that, it might be useful to also add the block height to the information retrieved, as in this case all the extension metadata will come from the same place.

Btw, If I am not mistaken all the information we want to fetch comes from the block header right now, so maybe a HeaderProvider trait with a function that returns the whole block header, and then stf_version and consensus_parameters_version and block_height can be provided methods?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think I'll prefer to extend (and rename) the "Consensus Parameters Provider". However, I find caching the entire block header not optimal and my preference would be to cache exactly what we need. So, in addition to the current data, it'll store:

  • current STF version
  • current block height

wdyt?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Currently, the STF version is cached in the "Consensus Parameters Provider", so we do not read from the DB every time, but handling of the current block height remains unchanged from the original implementation.


response
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::database::ReadView;

use crate::fuel_core_graphql_api::database::ReadDatabase;
use crate::{
fuel_core_graphql_api::database::ReadDatabase,
graphql_api::database::ReadView,
};
use async_graphql::{
extensions::{
Extension,
Expand Down
3 changes: 3 additions & 0 deletions crates/fuel-core/src/graphql_api/ports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,9 @@ pub trait ConsensusProvider: Send + Sync {
/// Returns latest consensus parameters.
fn latest_consensus_params(&self) -> Arc<ConsensusParameters>;

/// Returns latest consensus parameters version.
fn latest_consensus_parameters_version(&self) -> ConsensusParametersVersion;

fn consensus_params_at_version(
&self,
version: &ConsensusParametersVersion,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,14 @@ impl SharedState {
self.latest_consensus_parameters_with_version().1
}

pub fn latest_consensus_parameters_version(&self) -> ConsensusParametersVersion {
*self.latest_consensus_parameters_version.lock()
}

pub fn latest_consensus_parameters_with_version(
&self,
) -> (ConsensusParametersVersion, Arc<ConsensusParameters>) {
let version = *self.latest_consensus_parameters_version.lock();
let version = self.latest_consensus_parameters_version();
let params = self.get_consensus_parameters(&version)
.expect("The latest consensus parameters always are available unless this function was called before regenesis.");
(version, params)
Expand Down
4 changes: 4 additions & 0 deletions crates/fuel-core/src/service/adapters/graphql_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@ impl ConsensusProvider for ConsensusParametersProvider {
self.shared_state.latest_consensus_parameters()
}

fn latest_consensus_parameters_version(&self) -> ConsensusParametersVersion {
self.shared_state.latest_consensus_parameters_version()
}

fn consensus_params_at_version(
&self,
version: &ConsensusParametersVersion,
Expand Down
42 changes: 42 additions & 0 deletions tests/tests/graphql_extensions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use fuel_core::service::Config;
use fuel_core_bin::FuelService;
use serde_json::Value;
use test_helpers::send_graph_ql_query;

// TODO[RC]: Provide more detailed tests to verify that the correct STF and CP versions
// are returned.

#[tokio::test]
async fn extension_fields_are_present() {
const REQUIRED_FIELDS: [&str; 3] = [
"current_stf_version",
"current_fuel_block_height",
"current_consensus_parameters_version",
];

let node = FuelService::new_node(Config::local_node()).await.unwrap();
let url = format!("http://{}/v1/graphql", node.bound_address);

// Given
const QUERY: &str = r#"
query {
nodeInfo {
nodeVersion
}
}
"#;

// When
let response = send_graph_ql_query(&url, QUERY).await;

// Then
let json_value: Value =
serde_json::from_str(&response).expect("should be valid json");
let extensions = json_value
.get("extensions")
.expect("should have extensions");
for field in REQUIRED_FIELDS.iter() {
let is_field_present = extensions.get(field).is_some();
assert!(is_field_present)
}
}
2 changes: 2 additions & 0 deletions tests/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ mod fee_collection_contract;
#[cfg(not(feature = "only-p2p"))]
mod gas_price;
#[cfg(not(feature = "only-p2p"))]
mod graphql_extensions;
#[cfg(not(feature = "only-p2p"))]
mod health;
#[cfg(not(feature = "only-p2p"))]
mod helpers;
Expand Down
Loading