diff --git a/Cargo.lock b/Cargo.lock index 18ef4df744233..b27ebd7a56132 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13607,6 +13607,14 @@ dependencies = [ "tracing", ] +[[package]] +name = "sui-default-config" +version = "1.39.0" +dependencies = [ + "quote 1.0.35", + "syn 1.0.107", +] + [[package]] name = "sui-e2e-tests" version = "1.39.0" @@ -13865,14 +13873,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "sui-graphql-config" -version = "1.39.0" -dependencies = [ - "quote 1.0.35", - "syn 1.0.107", -] - [[package]] name = "sui-graphql-e2e-tests" version = "0.1.0" @@ -13935,8 +13935,8 @@ dependencies = [ "shared-crypto", "similar", "simulacrum", + "sui-default-config", "sui-framework", - "sui-graphql-config", "sui-graphql-rpc-client", "sui-graphql-rpc-headers", "sui-indexer", @@ -14590,8 +14590,8 @@ dependencies = [ "shared-crypto", "similar", "simulacrum", + "sui-default-config", "sui-framework", - "sui-graphql-config", "sui-graphql-rpc-client", "sui-graphql-rpc-headers", "sui-indexer", diff --git a/Cargo.toml b/Cargo.toml index c33adee27a8a6..d210b8214fbb8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -100,6 +100,7 @@ members = [ "crates/sui-data-ingestion", "crates/sui-data-ingestion-core", "crates/sui-deepbook-indexer", + "crates/sui-default-config", "crates/sui-e2e-tests", "crates/sui-enum-compat-util", "crates/sui-faucet", @@ -109,7 +110,6 @@ members = [ "crates/sui-framework-snapshot", "crates/sui-framework-tests", "crates/sui-genesis-builder", - "crates/sui-graphql-config", "crates/sui-graphql-e2e-tests", "crates/sui-graphql-rpc", "crates/sui-graphql-rpc-client", @@ -631,6 +631,7 @@ sui-core = { path = "crates/sui-core" } sui-cost = { path = "crates/sui-cost" } sui-data-ingestion = { path = "crates/sui-data-ingestion" } sui-data-ingestion-core = { path = "crates/sui-data-ingestion-core" } +sui-default-config = { path = "crates/sui-default-config" } sui-e2e-tests = { path = "crates/sui-e2e-tests" } sui-enum-compat-util = { path = "crates/sui-enum-compat-util" } sui-faucet = { path = "crates/sui-faucet" } @@ -639,7 +640,6 @@ sui-field-count-derive = { path = "crates/sui-field-count-derive" } sui-framework = { path = "crates/sui-framework" } sui-framework-snapshot = { path = "crates/sui-framework-snapshot" } sui-framework-tests = { path = "crates/sui-framework-tests" } -sui-graphql-config = { path = "crates/sui-graphql-config" } sui-graphql-rpc = { path = "crates/sui-graphql-rpc" } sui-graphql-rpc-client = { path = "crates/sui-graphql-rpc-client" } sui-graphql-rpc-headers = { path = "crates/sui-graphql-rpc-headers" } diff --git a/crates/sui-graphql-config/Cargo.toml b/crates/sui-default-config/Cargo.toml similarity index 88% rename from crates/sui-graphql-config/Cargo.toml rename to crates/sui-default-config/Cargo.toml index 0f20ce1769a94..8b0424bf5cbca 100644 --- a/crates/sui-graphql-config/Cargo.toml +++ b/crates/sui-default-config/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "sui-graphql-config" +name = "sui-default-config" version.workspace = true authors = ["Mysten Labs TokenStream { +pub fn DefaultConfig(_attr: TokenStream, input: TokenStream) -> TokenStream { let DeriveInput { attrs, vis, @@ -32,7 +30,7 @@ pub fn GraphQLConfig(_attr: TokenStream, input: TokenStream) -> TokenStream { semi_token, }) = data else { - panic!("GraphQL configs must be structs."); + panic!("Default configs must be structs."); }; let Fields::Named(FieldsNamed { @@ -40,12 +38,9 @@ pub fn GraphQLConfig(_attr: TokenStream, input: TokenStream) -> TokenStream { named, }) = fields else { - panic!("GraphQL configs must have named fields."); + panic!("Default configs must have named fields."); }; - // Figure out which derives need to be added to meet the criteria of a config struct. - let core_derives = core_derives(&attrs); - // Extract field names once to avoid having to check for their existence multiple times. let fields_with_names: Vec<_> = named .iter() @@ -73,14 +68,40 @@ pub fn GraphQLConfig(_attr: TokenStream, input: TokenStream) -> TokenStream { quote! { #[doc(hidden)] #cfg fn #fn_name() -> #ty { - Self::default().#name + ::default().#name } } }); + // Check if there's already a serde rename_all attribute + let has_rename_all = attrs.iter().any(|attr| { + if !attr.path.is_ident("serde") { + return false; + }; + + let Ok(Meta::List(MetaList { nested, .. })) = attr.parse_meta() else { + return false; + }; + + nested.iter().any(|nested| { + if let NestedMeta::Meta(Meta::NameValue(MetaNameValue { path, .. })) = nested { + path.is_ident("rename_all") + } else { + false + } + }) + }); + + // Only include the default rename_all if none exists + let rename_all = if !has_rename_all { + quote! { #[serde(rename_all = "kebab-case")] } + } else { + quote! {} + }; + TokenStream::from(quote! { - #[derive(#(#core_derives),*)] - #[serde(rename_all = "kebab-case")] + #[derive(serde::Serialize, serde::Deserialize)] + #rename_all #(#attrs)* #vis #struct_token #ident #generics { #(#fields),* } #semi_token @@ -91,49 +112,6 @@ pub fn GraphQLConfig(_attr: TokenStream, input: TokenStream) -> TokenStream { }) } -/// Return a set of derives that should be added to the struct to make sure it derives all the -/// things we expect from a config, namely `Serialize`, `Deserialize`, and `Debug`. -/// -/// We cannot add core derives unconditionally, because they will conflict with existing ones. -fn core_derives(attrs: &[Attribute]) -> BTreeSet { - let mut derives = BTreeSet::from_iter([ - format_ident!("Serialize"), - format_ident!("Deserialize"), - format_ident!("Debug"), - format_ident!("Clone"), - format_ident!("Eq"), - format_ident!("PartialEq"), - ]); - - for attr in attrs { - let Ok(Meta::List(list)) = attr.parse_meta() else { - continue; - }; - - let Some(ident) = list.path.get_ident() else { - continue; - }; - - if ident != "derive" { - continue; - } - - for nested in list.nested { - let NestedMeta::Meta(Meta::Path(path)) = nested else { - continue; - }; - - let Some(ident) = path.get_ident() else { - continue; - }; - - derives.remove(ident); - } - } - - derives -} - /// Find the attribute that corresponds to a `#[cfg(...)]` annotation, if it exists. fn extract_cfg(attrs: &[Attribute]) -> Option<&Attribute> { attrs.iter().find(|attr| { diff --git a/crates/sui-graphql-rpc/Cargo.toml b/crates/sui-graphql-rpc/Cargo.toml index f1c2b67842897..f58bd12123949 100644 --- a/crates/sui-graphql-rpc/Cargo.toml +++ b/crates/sui-graphql-rpc/Cargo.toml @@ -64,7 +64,7 @@ uuid.workspace = true im.workspace = true downcast = "0.11.0" -sui-graphql-config.workspace = true +sui-default-config.workspace = true sui-graphql-rpc-headers.workspace = true sui-graphql-rpc-client.workspace = true diff --git a/crates/sui-graphql-rpc/src/config.rs b/crates/sui-graphql-rpc/src/config.rs index cb9602fd7a0c6..56304bd2fd65e 100644 --- a/crates/sui-graphql-rpc/src/config.rs +++ b/crates/sui-graphql-rpc/src/config.rs @@ -9,7 +9,7 @@ use move_core_types::ident_str; use move_core_types::identifier::IdentStr; use serde::{Deserialize, Serialize}; use std::{collections::BTreeSet, fmt::Display, time::Duration}; -use sui_graphql_config::GraphQLConfig; +use sui_default_config::DefaultConfig; use sui_json_rpc::name_service::NameServiceConfig; use sui_types::base_types::{ObjectID, SuiAddress}; @@ -28,8 +28,8 @@ const MOVE_REGISTRY_TABLE_ID: &str = const DEFAULT_PAGE_LIMIT: u16 = 50; /// The combination of all configurations for the GraphQL service. -#[GraphQLConfig] -#[derive(Default)] +#[DefaultConfig] +#[derive(Clone, Default, Debug)] pub struct ServerConfig { pub service: ServiceConfig, pub connection: ConnectionConfig, @@ -41,8 +41,8 @@ pub struct ServerConfig { /// Configuration for connections for the RPC, passed in as command-line arguments. This configures /// specific connections between this service and other services, and might differ from instance to /// instance of the GraphQL service. -#[GraphQLConfig] -#[derive(clap::Args, Clone, Eq, PartialEq)] +#[DefaultConfig] +#[derive(clap::Args, Clone, Eq, PartialEq, Debug)] pub struct ConnectionConfig { /// Port to bind the server to #[clap(short, long, default_value_t = ConnectionConfig::default().port)] @@ -71,8 +71,8 @@ pub struct ConnectionConfig { /// Configuration on features supported by the GraphQL service, passed in a TOML-based file. These /// configurations are shared across fleets of the service, i.e. all testnet services will have the /// same `ServiceConfig`. -#[GraphQLConfig] -#[derive(Default)] +#[DefaultConfig] +#[derive(Clone, Default, Eq, PartialEq, Debug)] pub struct ServiceConfig { pub limits: Limits, pub disabled_features: BTreeSet, @@ -83,7 +83,8 @@ pub struct ServiceConfig { pub move_registry: MoveRegistryConfig, } -#[GraphQLConfig] +#[DefaultConfig] +#[derive(Clone, Eq, PartialEq, Debug)] pub struct Limits { /// Maximum depth of nodes in the requests. pub max_query_depth: u32, @@ -127,16 +128,16 @@ pub struct Limits { pub max_scan_limit: u32, } -#[GraphQLConfig] -#[derive(Copy)] +#[DefaultConfig] +#[derive(Copy, Clone, Eq, PartialEq, Debug)] pub struct BackgroundTasksConfig { /// How often the watermark task checks the indexer database to update the checkpoint and epoch /// watermarks. pub watermark_update_ms: u64, } -#[GraphQLConfig] -#[derive(Clone)] +#[DefaultConfig] +#[derive(Clone, Eq, PartialEq, Debug)] pub struct MoveRegistryConfig { pub(crate) external_api_url: Option, pub(crate) resolution_type: ResolutionType, @@ -185,16 +186,16 @@ impl Version { } } -#[GraphQLConfig] -#[derive(clap::Args)] +#[DefaultConfig] +#[derive(clap::Args, Clone, Debug)] pub struct Ide { /// The title to display at the top of the web-based GraphiQL IDE. #[clap(short, long, default_value_t = Ide::default().ide_title)] pub ide_title: String, } -#[GraphQLConfig] -#[derive(Default)] +#[DefaultConfig] +#[derive(Clone, Default, Eq, PartialEq, Debug)] pub struct Experiments { // Add experimental flags here, to provide access to them through-out the GraphQL // implementation. @@ -202,7 +203,8 @@ pub struct Experiments { test_flag: bool, } -#[GraphQLConfig] +#[DefaultConfig] +#[derive(Clone, Debug)] pub struct InternalFeatureConfig { pub(crate) query_limits_checker: bool, pub(crate) directive_checker: bool, @@ -215,16 +217,16 @@ pub struct InternalFeatureConfig { pub(crate) open_telemetry: bool, } -#[GraphQLConfig] -#[derive(clap::Args, Default)] +#[DefaultConfig] +#[derive(clap::Args, Clone, Default, Debug)] pub struct TxExecFullNodeConfig { /// RPC URL for the fullnode to send transactions to execute and dry-run. #[clap(long)] pub(crate) node_rpc_url: Option, } -#[GraphQLConfig] -#[derive(Default)] +#[DefaultConfig] +#[derive(Clone, Default, Eq, PartialEq, Debug)] pub struct ZkLoginConfig { pub env: ZkLoginEnv, } diff --git a/crates/sui-mvr-graphql-rpc/Cargo.toml b/crates/sui-mvr-graphql-rpc/Cargo.toml index 5db654e5122c1..39c88e978766f 100644 --- a/crates/sui-mvr-graphql-rpc/Cargo.toml +++ b/crates/sui-mvr-graphql-rpc/Cargo.toml @@ -64,7 +64,7 @@ uuid.workspace = true im.workspace = true downcast = "0.11.0" -sui-graphql-config.workspace = true +sui-default-config.workspace = true sui-graphql-rpc-headers.workspace = true sui-graphql-rpc-client.workspace = true diff --git a/crates/sui-mvr-graphql-rpc/src/config.rs b/crates/sui-mvr-graphql-rpc/src/config.rs index cb9602fd7a0c6..56304bd2fd65e 100644 --- a/crates/sui-mvr-graphql-rpc/src/config.rs +++ b/crates/sui-mvr-graphql-rpc/src/config.rs @@ -9,7 +9,7 @@ use move_core_types::ident_str; use move_core_types::identifier::IdentStr; use serde::{Deserialize, Serialize}; use std::{collections::BTreeSet, fmt::Display, time::Duration}; -use sui_graphql_config::GraphQLConfig; +use sui_default_config::DefaultConfig; use sui_json_rpc::name_service::NameServiceConfig; use sui_types::base_types::{ObjectID, SuiAddress}; @@ -28,8 +28,8 @@ const MOVE_REGISTRY_TABLE_ID: &str = const DEFAULT_PAGE_LIMIT: u16 = 50; /// The combination of all configurations for the GraphQL service. -#[GraphQLConfig] -#[derive(Default)] +#[DefaultConfig] +#[derive(Clone, Default, Debug)] pub struct ServerConfig { pub service: ServiceConfig, pub connection: ConnectionConfig, @@ -41,8 +41,8 @@ pub struct ServerConfig { /// Configuration for connections for the RPC, passed in as command-line arguments. This configures /// specific connections between this service and other services, and might differ from instance to /// instance of the GraphQL service. -#[GraphQLConfig] -#[derive(clap::Args, Clone, Eq, PartialEq)] +#[DefaultConfig] +#[derive(clap::Args, Clone, Eq, PartialEq, Debug)] pub struct ConnectionConfig { /// Port to bind the server to #[clap(short, long, default_value_t = ConnectionConfig::default().port)] @@ -71,8 +71,8 @@ pub struct ConnectionConfig { /// Configuration on features supported by the GraphQL service, passed in a TOML-based file. These /// configurations are shared across fleets of the service, i.e. all testnet services will have the /// same `ServiceConfig`. -#[GraphQLConfig] -#[derive(Default)] +#[DefaultConfig] +#[derive(Clone, Default, Eq, PartialEq, Debug)] pub struct ServiceConfig { pub limits: Limits, pub disabled_features: BTreeSet, @@ -83,7 +83,8 @@ pub struct ServiceConfig { pub move_registry: MoveRegistryConfig, } -#[GraphQLConfig] +#[DefaultConfig] +#[derive(Clone, Eq, PartialEq, Debug)] pub struct Limits { /// Maximum depth of nodes in the requests. pub max_query_depth: u32, @@ -127,16 +128,16 @@ pub struct Limits { pub max_scan_limit: u32, } -#[GraphQLConfig] -#[derive(Copy)] +#[DefaultConfig] +#[derive(Copy, Clone, Eq, PartialEq, Debug)] pub struct BackgroundTasksConfig { /// How often the watermark task checks the indexer database to update the checkpoint and epoch /// watermarks. pub watermark_update_ms: u64, } -#[GraphQLConfig] -#[derive(Clone)] +#[DefaultConfig] +#[derive(Clone, Eq, PartialEq, Debug)] pub struct MoveRegistryConfig { pub(crate) external_api_url: Option, pub(crate) resolution_type: ResolutionType, @@ -185,16 +186,16 @@ impl Version { } } -#[GraphQLConfig] -#[derive(clap::Args)] +#[DefaultConfig] +#[derive(clap::Args, Clone, Debug)] pub struct Ide { /// The title to display at the top of the web-based GraphiQL IDE. #[clap(short, long, default_value_t = Ide::default().ide_title)] pub ide_title: String, } -#[GraphQLConfig] -#[derive(Default)] +#[DefaultConfig] +#[derive(Clone, Default, Eq, PartialEq, Debug)] pub struct Experiments { // Add experimental flags here, to provide access to them through-out the GraphQL // implementation. @@ -202,7 +203,8 @@ pub struct Experiments { test_flag: bool, } -#[GraphQLConfig] +#[DefaultConfig] +#[derive(Clone, Debug)] pub struct InternalFeatureConfig { pub(crate) query_limits_checker: bool, pub(crate) directive_checker: bool, @@ -215,16 +217,16 @@ pub struct InternalFeatureConfig { pub(crate) open_telemetry: bool, } -#[GraphQLConfig] -#[derive(clap::Args, Default)] +#[DefaultConfig] +#[derive(clap::Args, Clone, Default, Debug)] pub struct TxExecFullNodeConfig { /// RPC URL for the fullnode to send transactions to execute and dry-run. #[clap(long)] pub(crate) node_rpc_url: Option, } -#[GraphQLConfig] -#[derive(Default)] +#[DefaultConfig] +#[derive(Clone, Default, Eq, PartialEq, Debug)] pub struct ZkLoginConfig { pub env: ZkLoginEnv, }