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

Estimate gas price API Endpoint #1650

Merged
merged 18 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Description of the upcoming release here.

### Changed

- [#1650](https://github.com/FuelLabs/fuel-core/pull/1650): Add api endpoint for getting estimates for future gas prices
- [#1649](https://github.com/FuelLabs/fuel-core/pull/1649): Add api endpoint for getting latest gas price
- [#1600](https://github.com/FuelLabs/fuel-core/pull/1640): Upgrade to fuel-vm 0.45.0
- [#1633](https://github.com/FuelLabs/fuel-core/pull/1633): Notify services about importing of the genesis block.
Expand Down
5 changes: 5 additions & 0 deletions crates/client/assets/schema.sdl
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,10 @@ type DryRunTransactionExecutionStatus {

union DryRunTransactionStatus = DryRunSuccessStatus | DryRunFailureStatus

type EstimateGasPrice {
gasPrice: U64!
}

input ExcludeInput {
"""
Utxos to exclude from the selection.
Expand Down Expand Up @@ -812,6 +816,7 @@ type Query {
contractBalances(filter: ContractBalanceFilterInput!, first: Int, after: String, last: Int, before: String): ContractBalanceConnection!
nodeInfo: NodeInfo!
latestGasPrice: LatestGasPrice!
estimateGasPrice(blockHorizon: U32): EstimateGasPrice!
message(nonce: Nonce!): Message
messages(owner: Address, first: Int, after: String, last: Int, before: String): MessageConnection!
messageProof(transactionId: TransactionId!, nonce: Nonce!, commitBlockId: BlockId, commitBlockHeight: U32): MessageProof
Expand Down
9 changes: 9 additions & 0 deletions crates/client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::client::{
SpendQueryElementInput,
},
contract::ContractBalanceQueryArgs,
gas_price::EstimateGasPrice,
message::MessageStatusArgs,
tx::DryRunArg,
Tai64Timestamp,
Expand Down Expand Up @@ -354,6 +355,14 @@ impl FuelClient {
self.query(query).await.map(|r| r.latest_gas_price.into())
}

pub async fn estimate_gas_price(
&self,
block_horizon: u32,
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it make more sense to accept block_horizon as an instance of BlockHorizon here, rather than converting in the function itself? Or maybe some T that can .into() into a BlockHorizon?

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't have a strong opinion either way, so I went with the precedence that had already been set, for example with client's endpoint block_by_height

pub async fn block_by_height(&self, height: u32) -> io::Result<Option<types::Block>> {
        let query = schema::block::BlockByHeightQuery::build(BlockByHeightArgs {
            height: Some(U32(height)),
        });

        let block = self.query(query).await?.block.map(Into::into);

        Ok(block)
    }

) -> io::Result<EstimateGasPrice> {
let query = schema::gas_price::QueryEstimateGasPrice::build(block_horizon.into());
self.query(query).await.map(|r| r.estimate_gas_price)
}

pub async fn connected_peers_info(&self) -> io::Result<Vec<PeerInfo>> {
let query = schema::node_info::QueryPeersInfo::build(());
self.query(query)
Expand Down
38 changes: 38 additions & 0 deletions crates/client/src/client/schema/gas_price.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,36 @@ pub struct QueryLatestGasPrice {
pub latest_gas_price: LatestGasPrice,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(schema_path = "./assets/schema.sdl")]
pub struct EstimateGasPrice {
pub gas_price: U64,
}

#[derive(cynic::QueryVariables, Debug)]
pub struct BlockHorizonArgs {
pub block_horizon: Option<U32>,
}

impl From<u32> for BlockHorizonArgs {
fn from(block_horizon: u32) -> Self {
Self {
block_horizon: Some(block_horizon.into()),
}
}
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(
schema_path = "./assets/schema.sdl",
graphql_type = "Query",
variables = "BlockHorizonArgs"
)]
pub struct QueryEstimateGasPrice {
#[arguments(blockHorizon: $block_horizon)]
pub estimate_gas_price: EstimateGasPrice,
}

#[cfg(test)]
mod tests {
use super::*;
Expand All @@ -27,4 +57,12 @@ mod tests {
let operation = QueryLatestGasPrice::build(());
insta::assert_snapshot!(operation.query)
}

#[test]
fn estimate_gas_price_query_gql_output() {
use cynic::QueryBuilder;
let arbitrary_horizon = 10;
let operation = QueryEstimateGasPrice::build(arbitrary_horizon.into());
insta::assert_snapshot!(operation.query)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
source: crates/client/src/client/schema/gas_price.rs
expression: operation.query
---
query($blockHorizon: U32) {
estimateGasPrice(blockHorizon: $blockHorizon) {
gasPrice
}
}


12 changes: 12 additions & 0 deletions crates/client/src/client/types/gas_price.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,15 @@ impl From<schema::gas_price::LatestGasPrice> for LatestGasPrice {
}
}
}

pub struct EstimateGasPrice {
pub gas_price: u64,
}

impl From<schema::gas_price::EstimateGasPrice> for EstimateGasPrice {
fn from(value: schema::gas_price::EstimateGasPrice) -> Self {
Self {
gas_price: value.gas_price.into(),
}
}
}
1 change: 1 addition & 0 deletions crates/fuel-core/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pub struct Query(
contract::ContractBalanceQuery,
node_info::NodeQuery,
gas_price::LatestGasPriceQuery,
gas_price::EstimateGasPriceQuery,
message::MessageQuery,
);

Expand Down
35 changes: 35 additions & 0 deletions crates/fuel-core/src/schema/gas_price.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,38 @@ impl LatestGasPriceQuery {
})
}
}

pub struct EstimateGasPrice {
pub gas_price: U64,
}

#[Object]
impl EstimateGasPrice {
async fn gas_price(&self) -> U64 {
self.gas_price
}
}

#[derive(Default)]
pub struct EstimateGasPriceQuery {}

#[Object]
impl EstimateGasPriceQuery {
async fn estimate_gas_price(
&self,
ctx: &Context<'_>,
#[graphql(
desc = "Number of blocks into the future to estimate the gas price for"
)]
block_horizon: Option<U32>,
) -> async_graphql::Result<EstimateGasPrice> {
// TODO: implement dynamic calculation based on block horizon
// https://github.com/FuelLabs/fuel-core/issues/1653
let _ = block_horizon;

let config = ctx.data_unchecked::<GraphQLConfig>();
let gas_price = config.min_gas_price.into();

Ok(EstimateGasPrice { gas_price })
}
}
2 changes: 1 addition & 1 deletion deployment/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Stage 1: Build
FROM --platform=$BUILDPLATFORM tonistiigi/xx AS xx
FROM --platform=$BUILDPLATFORM rust:1.73.0 AS chef
FROM --platform=$BUILDPLATFORM rust:1.74.0 AS chef

ARG TARGETPLATFORM
RUN cargo install cargo-chef
Expand Down
14 changes: 14 additions & 0 deletions tests/tests/gas_price.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use fuel_core::service::{
FuelService,
};
use fuel_core_client::client::{
schema::gas_price::EstimateGasPrice,
types::gas_price::LatestGasPrice,
FuelClient,
};
Expand All @@ -16,3 +17,16 @@ async fn latest_gas_price() {
let LatestGasPrice { gas_price, .. } = client.latest_gas_price().await.unwrap();
assert_eq!(gas_price, node_config.txpool.min_gas_price);
}

#[tokio::test]
async fn estimate_gas_price() {
let node_config = Config::local_node();
let srv = FuelService::new_node(node_config.clone()).await.unwrap();
let client = FuelClient::from(srv.bound_address);

let arbitrary_horizon = 10;

let EstimateGasPrice { gas_price } =
client.estimate_gas_price(arbitrary_horizon).await.unwrap();
assert_eq!(u64::from(gas_price), node_config.txpool.min_gas_price);
}
Loading