Skip to content

Commit

Permalink
feat: CLI arguments for configuring GraphQL query costs.
Browse files Browse the repository at this point in the history
Co-authored-by: Mårten Blankfors <marten@blankfors.se>
  • Loading branch information
acerone85 and netrome committed Oct 11, 2024
1 parent 5e272eb commit 7bf18ce
Show file tree
Hide file tree
Showing 20 changed files with 303 additions and 83 deletions.
24 changes: 24 additions & 0 deletions bin/fuel-core/src/cli/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use fuel_core::{
},
fuel_core_graphql_api::{
worker_service::DaCompressionConfig,
Costs,
ServiceConfig as GraphQLConfig,
},
producer::Config as ProducerConfig,
Expand Down Expand Up @@ -498,6 +499,29 @@ impl Command {
request_body_bytes_limit: graphql.graphql_request_body_bytes_limit,
api_request_timeout: graphql.api_request_timeout.into(),
query_log_threshold_time: graphql.query_log_threshold_time.into(),
costs: Costs {
balance_query: graphql.costs.balance_query,
coins_to_spend: graphql.costs.coins_to_spend,
get_peers: graphql.costs.get_peers,
estimate_predicates: graphql.costs.estimate_predicates,
dry_run: graphql.costs.dry_run,
submit: graphql.costs.submit,
submit_and_await: graphql.costs.submit_and_await,
status_change: graphql.costs.status_change,
storage_read: graphql.costs.storage_read,
tx_get: graphql.costs.tx_get,
tx_status_read: graphql.costs.tx_status_read,
tx_raw_payload: graphql.costs.tx_raw_payload,
block_header: graphql.costs.block_header,
block_transactions: graphql.costs.block_transactions,
block_transactions_ids: graphql.costs.block_transactions_ids,
storage_iterator: graphql.costs.storage_iterator,
bytecode_read: graphql.costs.bytecode_read,
state_transition_bytecode_read: graphql
.costs
.state_transition_bytecode_read,
da_compressed_block_read: graphql.costs.da_compressed_block_read,
},
},
combined_db_config,
snapshot_reader,
Expand Down
160 changes: 160 additions & 0 deletions bin/fuel-core/src/cli/run/graphql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

use std::net;

use fuel_core::fuel_core_graphql_api::DEFAULT_QUERY_COSTS;

#[derive(Debug, Clone, clap::Args)]
pub struct GraphQLArgs {
/// The IP address to bind the GraphQL service to.
Expand Down Expand Up @@ -55,4 +57,162 @@ pub struct GraphQLArgs {
/// Timeout before drop the request.
#[clap(long = "api-request-timeout", default_value = "30s", env)]
pub api_request_timeout: humantime::Duration,

#[clap(flatten)]
pub costs: QueryCosts,
}

/// Costs for individual graphql queries.
#[derive(Debug, Clone, clap::Args)]
pub struct QueryCosts {
/// Query costs for getting balances.
#[clap(
long = "query-cost-balance-query",
default_value = DEFAULT_QUERY_COSTS.balance_query.to_string(),
env
)]
pub balance_query: usize,

/// Query costs for getting coins to spend.
#[clap(
long = "query-cost-coins-to-spend",
default_value = DEFAULT_QUERY_COSTS.coins_to_spend.to_string(),
env)]
pub coins_to_spend: usize,

/// Query costs for getting peers.
#[clap(
long = "query-cost-get-peers",
default_value = DEFAULT_QUERY_COSTS.get_peers.to_string(),
env
)]
pub get_peers: usize,

/// Query costs for estimating predicates.
#[clap(
long = "query-cost-estimate-predicates",
default_value = DEFAULT_QUERY_COSTS.estimate_predicates.to_string(),
env
)]
pub estimate_predicates: usize,

/// Query costs for dry running a set of transactions.
#[clap(
long = "query-cost-dry-run",
default_value = DEFAULT_QUERY_COSTS.dry_run.to_string(),
env
)]
pub dry_run: usize,

/// Query costs for submitting a transaction.
#[clap(
long = "query-cost-submit",
default_value = DEFAULT_QUERY_COSTS.submit.to_string(),
env
)]
pub submit: usize,

/// Query costs for submitting and awaiting a transaction.
#[clap(
long = "query-cost-submit-and-await",
default_value = DEFAULT_QUERY_COSTS.submit_and_await.to_string(),
env
)]
pub submit_and_await: usize,

/// Query costs for the status change query.
#[clap(
long = "query-cost-status-change",
default_value = DEFAULT_QUERY_COSTS.status_change.to_string(),
env
)]
pub status_change: usize,

/// Query costs for reading from storage.
#[clap(
long = "query-cost-storage-read",
default_value = DEFAULT_QUERY_COSTS.storage_read.to_string(),
env
)]
pub storage_read: usize,

/// Query costs for getting a transaction.
#[clap(
long = "query-cost-tx-get",
default_value = DEFAULT_QUERY_COSTS.tx_get.to_string(),
env
)]
pub tx_get: usize,

/// Query costs for reading tx status.
#[clap(
long = "query-cost-tx-status-read",
default_value = DEFAULT_QUERY_COSTS.tx_status_read.to_string(),
env
)]
pub tx_status_read: usize,

/// Query costs for getting the raw tx payload.
#[clap(
long = "query-cost-tx-raw-payload",
default_value = DEFAULT_QUERY_COSTS.tx_raw_payload.to_string(),
env
)]
pub tx_raw_payload: usize,

/// Query costs for block header.
#[clap(
long = "query-cost-block-header",
default_value = DEFAULT_QUERY_COSTS.block_header.to_string(),
env
)]
pub block_header: usize,

/// Query costs for block transactions.
#[clap(
long = "query-cost-block-transactions",
default_value = DEFAULT_QUERY_COSTS.block_transactions.to_string(),
env
)]
pub block_transactions: usize,

/// Query costs for block transactions ids.
#[clap(
long = "query-cost-block-transactions-ids",
default_value = DEFAULT_QUERY_COSTS.block_transactions_ids.to_string(),
env
)]
pub block_transactions_ids: usize,

/// Query costs for iterating over storage entries.
#[clap(
long = "query-cost-storage-iterator",
default_value = DEFAULT_QUERY_COSTS.storage_iterator.to_string(),
env
)]
pub storage_iterator: usize,

/// Query costs for reading bytecode.
#[clap(
long = "query-cost-bytecode-read",
default_value = DEFAULT_QUERY_COSTS.bytecode_read.to_string(),
env
)]
pub bytecode_read: usize,

/// Query costs for reading state transition bytecode.
#[clap(
long = "query-cost-state-transition-bytecode-read",
default_value = DEFAULT_QUERY_COSTS.state_transition_bytecode_read.to_string(),
env
)]
pub state_transition_bytecode_read: usize,

/// Query costs for reading a DA compressed block.
#[clap(
long = "query-cost-da-compressed-block-read",
default_value = DEFAULT_QUERY_COSTS.da_compressed_block_read.to_string(),
env
)]
pub da_compressed_block_read: usize,
}
22 changes: 17 additions & 5 deletions crates/fuel-core/src/graphql_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use fuel_core_storage::{
};
use std::{
net::SocketAddr,
sync::OnceLock,
time::Duration,
};

Expand All @@ -30,8 +31,11 @@ pub struct ServiceConfig {
/// Time to wait after submitting a query before debug info will be logged about query.
pub query_log_threshold_time: Duration,
pub api_request_timeout: Duration,
/// Configurable cost parameters to limit graphql queries complexity
pub costs: Costs,
}

#[derive(Clone, Debug)]
pub struct Costs {
pub balance_query: usize,
pub coins_to_spend: usize,
Expand All @@ -54,16 +58,18 @@ pub struct Costs {
pub da_compressed_block_read: usize,
}

pub const QUERY_COSTS: Costs = Costs {
// balance_query: 4000,
impl Default for Costs {
fn default() -> Self {
DEFAULT_QUERY_COSTS
}
}

pub const DEFAULT_QUERY_COSTS: Costs = Costs {
balance_query: 40001,
coins_to_spend: 40001,
// get_peers: 2000,
get_peers: 40001,
// estimate_predicates: 3000,
estimate_predicates: 40001,
dry_run: 12000,
// submit: 5000,
submit: 40001,
submit_and_await: 40001,
status_change: 40001,
Expand All @@ -80,6 +86,12 @@ pub const QUERY_COSTS: Costs = Costs {
da_compressed_block_read: 4000,
};

pub fn query_costs() -> &'static Costs {
QUERY_COSTS.get().unwrap_or(&DEFAULT_QUERY_COSTS)
}

pub static QUERY_COSTS: OnceLock<Costs> = OnceLock::new();

#[derive(Clone, Debug)]
pub struct Config {
pub config: ServiceConfig,
Expand Down
6 changes: 6 additions & 0 deletions crates/fuel-core/src/graphql_api/api_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::{
view_extension::ViewExtension,
Config,
},
graphql_api::QUERY_COSTS,
schema::{
CoreSchema,
CoreSchemaBuilder,
Expand Down Expand Up @@ -220,6 +221,7 @@ where
OnChain::LatestView: OnChainDatabase,
OffChain::LatestView: OffChainDatabase,
{
initialize_query_costs(config.clone());
let network_addr = config.config.addr;
let combined_read_database =
ReadDatabase::new(genesis_block_height, on_database, off_database);
Expand Down Expand Up @@ -296,6 +298,10 @@ where
))
}

fn initialize_query_costs(config: Config) {
QUERY_COSTS.get_or_init(|| config.config.costs);
}

async fn graphql_playground() -> impl IntoResponse {
Html(playground_source(GraphQLPlaygroundConfig::new(
"/v1/graphql",
Expand Down
6 changes: 3 additions & 3 deletions crates/fuel-core/src/schema/balance.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
fuel_core_graphql_api::{
api_service::ConsensusProvider,
QUERY_COSTS,
query_costs,
},
query::BalanceQueryData,
schema::{
Expand Down Expand Up @@ -53,7 +53,7 @@ pub struct BalanceQuery;

#[Object]
impl BalanceQuery {
#[graphql(complexity = "QUERY_COSTS.balance_query")]
#[graphql(complexity = "query_costs().balance_query")]
async fn balance(
&self,
ctx: &Context<'_>,
Expand All @@ -71,7 +71,7 @@ impl BalanceQuery {

// TODO: This API should be migrated to the indexer for better support and
// discontinued within fuel-core.
#[graphql(complexity = "QUERY_COSTS.balance_query")]
#[graphql(complexity = "query_costs().balance_query")]
async fn balances(
&self,
ctx: &Context<'_>,
Expand Down
6 changes: 3 additions & 3 deletions crates/fuel-core/src/schema/blob.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
fuel_core_graphql_api::QUERY_COSTS,
fuel_core_graphql_api::query_costs,
graphql_api::IntoApiResult,
query::BlobQueryData,
schema::{
Expand Down Expand Up @@ -28,7 +28,7 @@ impl Blob {
self.0.into()
}

#[graphql(complexity = "QUERY_COSTS.bytecode_read")]
#[graphql(complexity = "query_costs().bytecode_read")]
async fn bytecode(&self, ctx: &Context<'_>) -> async_graphql::Result<HexString> {
let query = ctx.read_view()?;
query
Expand All @@ -49,7 +49,7 @@ pub struct BlobQuery;

#[Object]
impl BlobQuery {
#[graphql(complexity = "QUERY_COSTS.storage_read + child_complexity")]
#[graphql(complexity = "query_costs().storage_read + child_complexity")]
async fn blob(
&self,
ctx: &Context<'_>,
Expand Down
Loading

0 comments on commit 7bf18ce

Please sign in to comment.