diff --git a/crates/full-node/sov-rollup-apis/src/endpoints/constants.rs b/crates/full-node/sov-rollup-apis/src/endpoints/constants.rs index 49ea164a59..3340f38bd8 100644 --- a/crates/full-node/sov-rollup-apis/src/endpoints/constants.rs +++ b/crates/full-node/sov-rollup-apis/src/endpoints/constants.rs @@ -1,36 +1,63 @@ +use axum::extract::State; +use axum::response::IntoResponse as _; use axum::routing::get; use axum::Router; use serde::Serialize; -use sov_modules_api::macros::config_value; use sov_rest_utils::preconfigured_router_layers; +/// Trait for the `/rollup/constant` endpoint. +pub trait ConstantsEndpoint: Clone + Send + Sync + 'static { + /// The response data returned by the `schema` endpoint. + type Response: Serialize; + + /// Handles the `schema` request. + /// Should return the [`Constants`] as a JSON object string. + fn handler(&self) -> Self::Response; + + /// Returns a configured axum router for the schema endpoint. + /// + /// Calls the implemented [`ConstantsEndpoint::handler`] and returns the result. + /// If [`ConstantsEndpoint::handler`] returns a error then it will be included in the + /// [`sov_rest_utils::ErrorObject`]s details field. + /// + /// # Warning + /// + /// If you override this method you should ensure you provide the standard schema path. If the + /// path is different then external tooling like web3 SDKs won't be able to consume the + /// functionality and will fail to work. + fn axum_router(&self) -> Router<()> { + preconfigured_router_layers( + Router::new().route( + "/rollup/constants", + get(|State(state): State| async move { + axum::Json(state.handler()).into_response() + }) + .with_state(self.clone()), + ), + ) + } +} + /// The response returned by the `/rollup/constants` endpoint. /// /// For simplicity we currently only return a subset of constants that are useful /// for clientside applications. -#[derive(Serialize)] +#[derive(Serialize, Clone)] pub struct ConstantsResponse { - chain_id: u64, - chain_name: &'static str, - hyperlane_domain: u32, - address_prefix: &'static str, + /// the chain-id + pub chain_id: u64, + /// the chain-name + pub chain_name: String, + /// hyperlane domain for warp routes + pub hyperlane_domain: u32, + /// the address prefix + pub address_prefix: &'static str, } -impl Default for ConstantsResponse { - fn default() -> Self { - Self { - chain_id: config_value!("CHAIN_ID"), - chain_name: config_value!("CHAIN_NAME"), - hyperlane_domain: config_value!("HYPERLANE_BRIDGE_DOMAIN"), - address_prefix: config_value!("ADDRESS_PREFIX"), - } - } -} +impl ConstantsEndpoint for ConstantsResponse { + type Response = Self; -/// Returns an axum router configured to serve `/rollup/constants` requests -pub fn axum_router() -> Router<()> { - preconfigured_router_layers(Router::new().route( - "/rollup/constants", - get(|| async move { axum::Json(ConstantsResponse::default()) }), - )) + fn handler(&self) -> Self::Response { + self.clone() + } } diff --git a/crates/full-node/sov-rollup-apis/src/endpoints/simulate.rs b/crates/full-node/sov-rollup-apis/src/endpoints/simulate.rs index 2e5fd9b8c9..2614416742 100644 --- a/crates/full-node/sov-rollup-apis/src/endpoints/simulate.rs +++ b/crates/full-node/sov-rollup-apis/src/endpoints/simulate.rs @@ -14,7 +14,6 @@ use sov_modules_api::capabilities::{ AuthorizationData, ChainState, TransactionAuthorizer, UniquenessData, }; use sov_modules_api::common::Amount; -use sov_modules_api::macros::config_value; use sov_modules_api::prelude::anyhow; use sov_modules_api::sov_universal_wallet::schema::{RollupRoots, SchemaError}; use sov_modules_api::transaction::{Credentials, PriorityFeeBips, TxDetails}; @@ -271,7 +270,7 @@ impl> SovereignSimulate { .transpose() .map_err(|e| SimulateError::InvalidInput(format!("{e:?}")))?; Ok(TxDetails { - chain_id: config_value!("CHAIN_ID"), + chain_id: *sov_modules_api::CHAIN_ID, max_priority_fee_bips: partial .max_priority_fee_bips .unwrap_or(PriorityFeeBips::ZERO), diff --git a/crates/module-system/module-implementations/sov-evm/src/authenticate.rs b/crates/module-system/module-implementations/sov-evm/src/authenticate.rs index d3904ccc79..705d03dda1 100644 --- a/crates/module-system/module-implementations/sov-evm/src/authenticate.rs +++ b/crates/module-system/module-implementations/sov-evm/src/authenticate.rs @@ -14,7 +14,6 @@ use sov_modules_api::capabilities::{ BatchFromUnregisteredSequencer, FatalError, TransactionAuthenticator, UniquenessData, UnregisteredAuthenticationError, }; -use sov_modules_api::macros::config_value; use sov_modules_api::runtime::capabilities::AuthenticationError; use sov_modules_api::transaction::{ AuthenticatedTransactionAndRawHash, AuthenticatedTransactionData, Credentials, PriorityFeeBips, @@ -22,6 +21,7 @@ use sov_modules_api::transaction::{ }; use sov_modules_api::StateReader; use sov_modules_api::VersionReader; +use sov_modules_api::CHAIN_ID; use sov_modules_api::{ DispatchCall, FullyBakedTx, Gas, GetGasPrice, ProvableStateReader, RawTx, Runtime, Spec, }; @@ -184,7 +184,7 @@ fn validate_chain_id( tx_chain_id: Option, tx_hash: TxHash, ) -> Result { - let rollup_chain_id = config_value!("CHAIN_ID"); + let rollup_chain_id = *CHAIN_ID; let tx_chain_id = tx_chain_id.ok_or(AuthenticationError::FatalError( FatalError::MissingChainId(rollup_chain_id), tx_hash, @@ -284,7 +284,7 @@ where ))?; let tx_chain_id = match request.chain_id { Some(chain_id) => validate_chain_id(Some(chain_id), sentinel_tx_hash)?, - None => config_value!("CHAIN_ID"), + None => *CHAIN_ID, }; let authenticated_tx = build_authenticated_tx_data::<_, S>( sentinel_tx_hash, @@ -450,7 +450,8 @@ where let (tx_and_raw_hash, auth_data, runtime_call) = sov_modules_api::capabilities::authenticate::<_, S, Rt>( &tx.data, - &Rt::CHAIN_HASH, + *CHAIN_ID, + &Rt::chain_hash(), state, )?; diff --git a/crates/module-system/sov-cli/src/workflows/transactions.rs b/crates/module-system/sov-cli/src/workflows/transactions.rs index bd464797aa..8e93d31b31 100644 --- a/crates/module-system/sov-cli/src/workflows/transactions.rs +++ b/crates/module-system/sov-cli/src/workflows/transactions.rs @@ -208,7 +208,7 @@ where Ok(UnsignedTransactionWithoutUniqueness::new( tx, chain_id, - RT::CHAIN_HASH, + RT::chain_hash(), max_priority_fee_bips.into(), max_fee, gas_limit, diff --git a/crates/module-system/sov-eip712-auth/src/lib.rs b/crates/module-system/sov-eip712-auth/src/lib.rs index 62905d4bbe..ee666a12af 100644 --- a/crates/module-system/sov-eip712-auth/src/lib.rs +++ b/crates/module-system/sov-eip712-auth/src/lib.rs @@ -13,7 +13,7 @@ use sov_modules_api::transaction::{ }; use sov_modules_api::{ DispatchCall, FullyBakedTx, GasMeter, MeteredBorshDeserialize, MeteredBorshDeserializeError, - ProvableStateReader, RawTx, Runtime, Spec, TxHash, VersionReader, + ProvableStateReader, RawTx, Runtime, Spec, TxHash, VersionReader, CHAIN_ID, }; use sov_state::User; @@ -130,7 +130,8 @@ where Eip712AuthenticatorInput::Standard(tx) => { sov_modules_api::capabilities::authenticate::<_, S, Rt>( &tx.data, - &Rt::CHAIN_HASH, + *CHAIN_ID, + &Rt::chain_hash(), state, ) } @@ -255,7 +256,7 @@ fn verify_and_decode_tx< } }; - verify_chain_id(details, raw_tx_hash)?; + verify_chain_id(details, raw_tx_hash, *CHAIN_ID)?; verify_eip712_signature::(&tx, raw_tx_hash, meter)?; let tx_and_raw_hash = AuthenticatedTransactionAndRawHash { diff --git a/crates/module-system/sov-modules-api/src/runtime/capabilities/authentication.rs b/crates/module-system/sov-modules-api/src/runtime/capabilities/authentication.rs index 1efdd6f9dc..41332abc76 100644 --- a/crates/module-system/sov-modules-api/src/runtime/capabilities/authentication.rs +++ b/crates/module-system/sov-modules-api/src/runtime/capabilities/authentication.rs @@ -18,15 +18,16 @@ use crate::transaction::{ #[cfg(feature = "native")] use crate::CryptoSpecExt; use crate::GetGasPrice; +use crate::CHAIN_ID; use crate::{ capabilities, CryptoSpec, DispatchCall, FullyBakedTx, GasMeter, GasMeteringError, MeteredBorshDeserialize, MeteredBorshDeserializeError, MeteredHasher, ProvableStateReader, RawTx, Runtime, Spec, VersionReader, }; -/// The chain ID of the rollup. +/// The default chain ID of the rollup. pub fn config_chain_id() -> u64 { - config_value_private!("CHAIN_ID") + *CHAIN_ID } /// Resolves all valid chain hashes for a given height using configured overrides. @@ -212,7 +213,12 @@ where capabilities::fatal_deserialization_error::<_, S, _>(&tx.data, e, pre_exec_ws) })?; - crate::capabilities::authenticate::<_, S, Rt>(&input.data, &Rt::CHAIN_HASH, pre_exec_ws) + crate::capabilities::authenticate::<_, S, Rt>( + &input.data, + *CHAIN_ID, + &Rt::chain_hash(), + pre_exec_ws, + ) } #[cfg(feature = "native")] @@ -351,11 +357,12 @@ impl From for UnregisteredAuthenticationError { pub fn verify_chain_id( tx_details: &TxDetails, raw_tx_hash: TxHash, + expected_chain_id: u64, ) -> Result<(), AuthenticationError> { - if tx_details.chain_id != config_chain_id() { + if tx_details.chain_id != expected_chain_id { return Err(AuthenticationError::FatalError( FatalError::InvalidChainId { - expected: config_chain_id(), + expected: expected_chain_id, got: tx_details.chain_id, }, raw_tx_hash, @@ -420,6 +427,7 @@ fn verify_signature>( pub fn verify_and_decode_tx>( raw_tx_hash: TxHash, tx: Transaction, + expected_chain_id: u64, chain_hash: &[u8; 32], meter: &mut impl GasMeter, ) -> Result, AuthenticationError> { @@ -427,7 +435,7 @@ pub fn verify_and_decode_tx>( primary: *chain_hash, grace_period_hashes: Vec::new(), }; - verify_and_decode_tx_multi_hash(raw_tx_hash, tx, resolved_hashes, meter) + verify_and_decode_tx_multi_hash(raw_tx_hash, tx, expected_chain_id, resolved_hashes, meter) } /// Authenticate raw sov-transaction. @@ -445,6 +453,7 @@ pub fn authenticate< D: DispatchCall, >( mut raw_tx: &[u8], + expected_chain_id: u64, default_chain_hash: &[u8; 32], state: &mut Accessor, ) -> Result, AuthenticationError> { @@ -483,7 +492,13 @@ pub fn authenticate< )); } - verify_and_decode_tx_multi_hash::(raw_tx_hash, tx, resolved_hashes, state) + verify_and_decode_tx_multi_hash::( + raw_tx_hash, + tx, + expected_chain_id, + resolved_hashes, + state, + ) } /// Authenticate and verify deserialized sov-tx with multiple chain hashes. @@ -493,6 +508,7 @@ pub fn authenticate< fn verify_and_decode_tx_multi_hash>( raw_tx_hash: TxHash, tx: Transaction, + expected_chain_id: u64, resolved_hashes: crate::runtime::ResolvedChainHashes, meter: &mut impl GasMeter, ) -> Result, AuthenticationError> { @@ -508,7 +524,7 @@ fn verify_and_decode_tx_multi_hash>( } }; - verify_chain_id(details, raw_tx_hash)?; + verify_chain_id(details, raw_tx_hash, expected_chain_id)?; // Try signature verification with each valid chain hash let mut last_error = None; @@ -548,12 +564,16 @@ pub fn authenticate_unregistered< pre_exec_ws: &mut Accessor, ) -> Result, UnregisteredAuthenticationError> { let (tx_and_raw_hash, auth_data, runtime_call) = - authenticate::<_, S, Rt>(raw_tx, &Rt::CHAIN_HASH, pre_exec_ws).map_err(|e| match e { - AuthenticationError::FatalError(err, hash) => { - UnregisteredAuthenticationError::FatalError(err, hash) - } - AuthenticationError::OutOfGas(err) => UnregisteredAuthenticationError::OutOfGas(err), - })?; + authenticate::<_, S, Rt>(raw_tx, *CHAIN_ID, &Rt::chain_hash(), pre_exec_ws).map_err( + |e| match e { + AuthenticationError::FatalError(err, hash) => { + UnregisteredAuthenticationError::FatalError(err, hash) + } + AuthenticationError::OutOfGas(err) => { + UnregisteredAuthenticationError::OutOfGas(err) + } + }, + )?; Ok((tx_and_raw_hash, auth_data, runtime_call)) } diff --git a/crates/module-system/sov-modules-api/src/runtime/mod.rs b/crates/module-system/sov-modules-api/src/runtime/mod.rs index 2f7bd4c748..57cb456b63 100644 --- a/crates/module-system/sov-modules-api/src/runtime/mod.rs +++ b/crates/module-system/sov-modules-api/src/runtime/mod.rs @@ -7,9 +7,12 @@ use std::io; use borsh::{BorshDeserialize, BorshSerialize}; use capabilities::{HasCapabilities, HasKernel, TimelockPolicy, TransactionAuthenticator}; use serde::{Deserialize, Serialize}; + #[cfg(feature = "native")] use sov_rollup_interface::stf::GenesisParams; +use crate::sov_universal_wallet::schema::ChainData; + #[cfg(feature = "native")] use crate::hooks::FinalizeHook; use crate::hooks::{BlockHooks, TxHooks}; @@ -62,6 +65,33 @@ impl ModuleExecutionConfig for () { } } + +sov_modules_macros::static_bytes!(CONSTANTS, "constants.toml"); + +use std::sync::LazyLock; + +/// Get a field from the CONSTANTS. +pub fn get_from_constants(section: &str, key: &str) -> Option { + let value = str::from_utf8(CONSTANTS.as_ref()).expect("not a string"); + let value: toml::Table = toml::from_str(value).expect("no TOML format"); + let value = value.get(section).expect("no section"); + Some(value.as_table().and_then(|x| x.get(key))?.to_string()) + +} + +/// The CHAIN_NAME as extracted from the CONSTANTS. +pub static CHAIN_NAME: LazyLock = LazyLock::new(|| { + let mut res = get_from_constants("constants", "CHAIN_NAME").expect("no CHAIN_NAME"); + // drop the quotation marks + res.retain(|x| x != '"'); + res +}); + +/// The CHAIN_ID as extracted from the CONSTANTS. +pub static CHAIN_ID: LazyLock = LazyLock::new(|| { + get_from_constants("constants", "CHAIN_ID").expect("no CHAIN_ID").parse().expect("invalud CHAIN_ID") +}); + #[cfg(feature = "native")] /// This trait has to be implemented by a runtime in order to be used in `StfBlueprint`. /// @@ -79,10 +109,6 @@ pub trait Runtime: + RuntimeEventProcessor + 'static { - /// Chain root hash used for transaction verification. Generated from a - /// [schema](crate::sov_universal_wallet::schema::Schema). - const CHAIN_HASH: [u8; 32]; - /// GenesisConfig type. type GenesisConfig: Clone + Send + Sync + GenesisParams; @@ -105,6 +131,10 @@ pub trait Runtime: /// Default RPC methods and Axum router. fn endpoints(storage: crate::rest::ApiState) -> NodeEndpoints; + /// Chain root hash used for transaction verification. Generated from a + /// [schema](crate::sov_universal_wallet::schema::Schema). + fn chain_hash() -> [u8; 32]; + /// Reads genesis configs. fn genesis_config(input: &Self::GenesisInput) -> anyhow::Result; @@ -198,7 +228,10 @@ pub trait Runtime: { /// Chain root hash used for transaction verification. Generated from a /// [schema](crate::sov_universal_wallet::schema::Schema). - const CHAIN_HASH: [u8; 32]; + fn chain_hash() -> [u8; 32]; + + /// Overridable chain-id. + fn chain_id() -> u64; /// `GenesisConfig` type. type GenesisConfig: Clone + Send + Sync; @@ -250,16 +283,16 @@ impl Default for NodeEndpoints { } /// Helper function to get [`sov_universal_wallet::schema::Schema`] for the [`Runtime`] -pub fn get_runtime_schema( +pub fn get_runtime_schema + 'static>( ) -> anyhow::Result { let schema = sov_universal_wallet::schema::Schema::of_rollup_types_with_chain_data::< crate::transaction::Transaction, crate::transaction::UnsignedTransaction, R::Decodable, S::Address, - >(sov_universal_wallet::schema::ChainData { - chain_id: sov_modules_macros::config_value!("CHAIN_ID"), - chain_name: sov_modules_macros::config_value!("CHAIN_NAME").to_string(), + >(ChainData { + chain_id: *CHAIN_ID, + chain_name: CHAIN_NAME.to_string(), })?; Ok(schema) } diff --git a/crates/module-system/sov-modules-macros/src/lib.rs b/crates/module-system/sov-modules-macros/src/lib.rs index 0aa50a121c..6e63504451 100644 --- a/crates/module-system/sov-modules-macros/src/lib.rs +++ b/crates/module-system/sov-modules-macros/src/lib.rs @@ -128,6 +128,7 @@ mod cli_parser; mod common; mod compile_manifest_constants; +mod static_bytes; mod dispatch; mod event; mod expand_macro; @@ -144,6 +145,7 @@ mod rpc; mod metrics; use compile_manifest_constants::{make_const_value, ConfigValueInput}; +use static_bytes::{make_static_bytes, StaticBytesInput}; use dispatch::dispatch_call::DispatchCallMacro; use dispatch::genesis::GenesisMacro; use dispatch::hooks::HooksMacro; @@ -315,6 +317,12 @@ pub fn config_value_private(item: TokenStream) -> TokenStream { handle_macro_error_and_expand(fn_name!(), tokens) } +#[proc_macro] +pub fn static_bytes(item: TokenStream) -> TokenStream { + let input = syn::parse_macro_input!(item as StaticBytesInput); + handle_macro_error_and_expand(fn_name!(), make_static_bytes(&input).map(Into::into)) +} + #[cfg(any(feature = "native", feature = "bench"))] struct AttributeArgs(syn::punctuated::Punctuated); diff --git a/crates/module-system/sov-modules-macros/src/static_bytes.rs b/crates/module-system/sov-modules-macros/src/static_bytes.rs new file mode 100644 index 0000000000..f18e5e297f --- /dev/null +++ b/crates/module-system/sov-modules-macros/src/static_bytes.rs @@ -0,0 +1,65 @@ +use proc_macro2::{Ident, Span, TokenStream}; +use std::{fs, path::PathBuf}; +use syn::punctuated::Punctuated; + +#[derive(Clone)] +pub struct StaticBytesInput { + pub name: Ident, + pub file: syn::LitStr, +} + + +impl syn::parse::Parse for StaticBytesInput { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let name = input.parse()?; + let _: syn::Token![,] = input.parse()?; + let file = input.parse()?; + + Ok(Self { + name, + file, + }) + } +} + + +pub fn make_static_bytes(input: &StaticBytesInput) -> syn::Result { + let mut path = PathBuf::new(); + path.push(env!("CONSTANTS_MANIFEST_PATH")); + path.pop(); + path.push(input.file.value()); + + let content = fs::read_to_string(&path).map_err(|e| { + syn::Error::new( + input.file.span(), + format!("failed to read `{}`: {}", path.display(), e), + )})?; + + let len = content.len(); + let elems = content.as_bytes().iter().map(|b| { + let lit = syn::LitInt::new(&format!("{b}u8"), Span::call_site()); + syn::Expr::Lit(syn::ExprLit { + attrs: Vec::new(), + lit: syn::Lit::Int(lit), + }) + }); + let content = syn::Expr::Array(syn::ExprArray { + attrs: Vec::new(), + bracket_token: syn::token::Bracket::default(), + elems: Punctuated::from_iter(elems), + }); + + let name = quote::format_ident!("{}", input.name); + + // MacOS has a different convention for section names. + #[cfg(target_os = "macos")] + let link_section = format!("__DATA,__{}", name); + #[cfg(target_os = "linux")] + let link_section = format!(".data.{}", name); + + + Ok(quote::quote!( + #[unsafe(link_section = #link_section)] + static #name : [u8; #len] = #content; + )) +} diff --git a/crates/module-system/sov-modules-macros/tests/integration/regression_tests/derive_rpc_without_working_set_deny_missing_docs.rs b/crates/module-system/sov-modules-macros/tests/integration/regression_tests/derive_rpc_without_working_set_deny_missing_docs.rs index 446a6391f4..800a0cb5fa 100644 --- a/crates/module-system/sov-modules-macros/tests/integration/regression_tests/derive_rpc_without_working_set_deny_missing_docs.rs +++ b/crates/module-system/sov-modules-macros/tests/integration/regression_tests/derive_rpc_without_working_set_deny_missing_docs.rs @@ -14,6 +14,7 @@ pub struct TestStruct { } #[rpc_gen(client, server, namespace = "test")] +#[allow(dead_code)] impl TestStruct { #[rpc_method(name = "foo")] pub fn foo(&self) -> jsonrpsee::core::RpcResult { diff --git a/crates/module-system/sov-solana-offchain-auth/src/authentication/mod.rs b/crates/module-system/sov-solana-offchain-auth/src/authentication/mod.rs index 1d157eb6b7..02e499d814 100644 --- a/crates/module-system/sov-solana-offchain-auth/src/authentication/mod.rs +++ b/crates/module-system/sov-solana-offchain-auth/src/authentication/mod.rs @@ -232,8 +232,9 @@ where pub fn authenticate( raw_tx: &[u8], + runtime_chain_id: u64, runtime_chain_hash: &[u8; 32], - runtime_chain_name: &'static str, + runtime_chain_name: &str, state: &mut Accessor, ) -> Result, AuthenticationError> where @@ -309,7 +310,7 @@ where )); } - verify_chain_id(&unsigned_tx.details, raw_tx_hash)?; + verify_chain_id(&unsigned_tx.details, raw_tx_hash, runtime_chain_id)?; // Verify signatures (branches internally for single-sig vs multisig) verify_signatures::(&unpacked_message, raw_tx_hash, state)?; diff --git a/crates/module-system/sov-solana-offchain-auth/src/capabilities.rs b/crates/module-system/sov-solana-offchain-auth/src/capabilities.rs index 839be6bc74..f78f6a8347 100644 --- a/crates/module-system/sov-solana-offchain-auth/src/capabilities.rs +++ b/crates/module-system/sov-solana-offchain-auth/src/capabilities.rs @@ -6,9 +6,9 @@ use serde::Serialize; use sov_modules_api::capabilities::{ BatchFromUnregisteredSequencer, TransactionAuthenticator, UnregisteredAuthenticationError, }; -use sov_modules_api::macros::config_value; use sov_modules_api::{ - DispatchCall, FullyBakedTx, ProvableStateReader, RawTx, Runtime, Spec, VersionReader, + DispatchCall, FullyBakedTx, ProvableStateReader, RawTx, Runtime, Spec, VersionReader, CHAIN_ID, + CHAIN_NAME, }; /// Indicates that a runtime supports the `SolanaOffchain` transaction authenticator @@ -88,8 +88,9 @@ where let (tx_and_raw_hash, auth_data, runtime_call) = crate::authentication::authenticate::( &tx.data, - &Rt::CHAIN_HASH, - config_value!("CHAIN_NAME"), + *CHAIN_ID, + &Rt::chain_hash(), + &CHAIN_NAME, state, )?; @@ -99,7 +100,8 @@ where let (tx_and_raw_hash, auth_data, runtime_call) = sov_modules_api::capabilities::authenticate::<_, S, Rt>( &tx.data, - &Rt::CHAIN_HASH, + *CHAIN_ID, + &Rt::chain_hash(), state, )?; @@ -140,8 +142,9 @@ where let (tx_and_raw_hash, auth_data, runtime_call) = crate::authentication::authenticate::( &tx.data, - &Rt::CHAIN_HASH, - config_value!("CHAIN_NAME"), + *CHAIN_ID, + &Rt::chain_hash(), + &CHAIN_NAME, state, )?; Ok((tx_and_raw_hash, auth_data, runtime_call)) diff --git a/crates/utils/sov-build/src/lib.rs b/crates/utils/sov-build/src/lib.rs index be76a11d7e..91ca7b73d0 100644 --- a/crates/utils/sov-build/src/lib.rs +++ b/crates/utils/sov-build/src/lib.rs @@ -1,7 +1,7 @@ //! Build utilities for Sovereign SDK rollups. //! //! This crate provides tools for generating artifacts during the build process of Sovereign SDK rollups, -//! including runtime schema generation and JSON schema output. +//! including JSON schema output. use std::fs::File; use std::io::{BufWriter, Write}; @@ -68,7 +68,6 @@ where pub struct OptionsBuilder { out_dir: PathBuf, rust_autogenerated_path: Option, - rollup_schema: bool, json_schema: bool, set_git_hash: bool, } @@ -78,7 +77,6 @@ impl Default for OptionsBuilder { Self { out_dir: PathBuf::from(".artifacts"), rust_autogenerated_path: None, - rollup_schema: false, json_schema: true, set_git_hash: false, } @@ -102,14 +100,6 @@ impl OptionsBuilder { self } - /// Controls whether to generate rollup schema JSON file. - /// - /// Default: `true` - pub fn rollup_schema(mut self, enabled: bool) -> Self { - self.rollup_schema = enabled; - self - } - /// Controls whether to generate JSON schema file. /// /// Default: `true` @@ -132,7 +122,6 @@ impl OptionsBuilder { Options { out_dir: self.out_dir, rust_autogenerated_path: self.rust_autogenerated_path, - rollup_schema: self.rollup_schema, json_schema: self.json_schema, set_git_hash: self.set_git_hash, } @@ -145,7 +134,6 @@ impl OptionsBuilder { pub struct Options { pub out_dir: PathBuf, pub rust_autogenerated_path: Option, - pub rollup_schema: bool, pub json_schema: bool, pub set_git_hash: bool, } @@ -169,7 +157,6 @@ impl Options { /// fn main() -> anyhow::Result<()> { /// let options = Options::builder() /// .out_dir("build/artifacts") - /// .rollup_schema(true) /// .json_schema(false) /// .build() /// .apply::>() @@ -182,16 +169,11 @@ impl Options { D::Decodable: JsonSchema, { std::fs::create_dir_all(&self.out_dir)?; - self.output_rust_constants::()?; if self.set_git_hash { self.set_git_head_env()?; } - if self.rollup_schema { - self.output_rollup_schema::()?; - } - if self.json_schema { self.output_json_schema::()?; } @@ -219,53 +201,6 @@ impl Options { Self::builder().build().apply::() } - fn output_rust_constants(&self) -> anyhow::Result<()> - where - S: Spec, - D: DispatchCall + TransactionCallable + 'static, - { - let out_path = self - .rust_autogenerated_path - .clone() - .unwrap_or_else(|| self.out_dir.join("autogenerated.rs")); - let schema = - sov_modules_api::runtime::get_runtime_schema::().expect("Failed to get schema"); - - let schema_json = serde_json::to_string_pretty(&schema)?; - let schema_borsh = borsh::to_vec(&schema)?; - let chain_hash = schema.chain_hash().unwrap(); - - write_atomically(&out_path, |file| { - write!(file, "pub const CHAIN_HASH: [u8; 32] = {chain_hash:?};\n\n")?; - write!( - file, - "#[allow(dead_code)]\npub const SCHEMA_BORSH: &[u8] = &{schema_borsh:?};\n\n" - )?; - write!( - file, - "#[allow(dead_code)]\npub const SCHEMA_JSON: &str = r#\"{schema_json}\"#;\n" - )?; - Ok(()) - }) - } - - fn output_rollup_schema(&self) -> anyhow::Result<()> - where - S: Spec, - D: DispatchCall + TransactionCallable + 'static, - { - let out_path = self.out_dir.join("rollup-schema.json"); - let schema = - sov_modules_api::runtime::get_runtime_schema::().expect("Failed to get schema"); - let json = serde_json::to_string_pretty(&schema)?; - - write_atomically(&out_path, |file| { - file.write_all(json.as_bytes())?; - file.write_all(b"\n")?; - Ok(()) - }) - } - fn output_json_schema(&self) -> anyhow::Result<()> where D: DispatchCall + TransactionCallable + 'static, diff --git a/crates/utils/sov-test-utils/src/generators/mod.rs b/crates/utils/sov-test-utils/src/generators/mod.rs index 8550a3965b..a7d2ada2cf 100644 --- a/crates/utils/sov-test-utils/src/generators/mod.rs +++ b/crates/utils/sov-test-utils/src/generators/mod.rs @@ -64,7 +64,7 @@ impl Message { ) -> sov_modules_api::transaction::Transaction { Transaction::::new_signed_tx( &self.sender_key, - &RT::CHAIN_HASH, + &RT::chain_hash(), UnsignedTransaction::new( >::to_decodable(self.content), self.details.chain_id, diff --git a/crates/utils/sov-test-utils/src/interface/inputs.rs b/crates/utils/sov-test-utils/src/interface/inputs.rs index 824d756b74..9119f9227f 100644 --- a/crates/utils/sov-test-utils/src/interface/inputs.rs +++ b/crates/utils/sov-test-utils/src/interface/inputs.rs @@ -112,7 +112,7 @@ impl, S: Spec> TransactionType { } => RT::Auth::encode_with_standard_auth(Self::sign_and_serialize( message, key, - &RT::CHAIN_HASH, + &RT::chain_hash(), details, nonces, )), diff --git a/crates/utils/sov-test-utils/src/runtime/macros.rs b/crates/utils/sov-test-utils/src/runtime/macros.rs index f07ef70ab5..8c7874659d 100644 --- a/crates/utils/sov-test-utils/src/runtime/macros.rs +++ b/crates/utils/sov-test-utils/src/runtime/macros.rs @@ -113,6 +113,7 @@ macro_rules! generate_runtime_without_capabilities { } } } + use ::sov_modules_api::macros::config_value; impl $crate::runtime::Runtime for $id where @@ -121,8 +122,6 @@ macro_rules! generate_runtime_without_capabilities { ::Decodable: $crate::sov_universal_wallet::schema::UniversalWallet, $($runtime_trait_impl_bounds)* { - const CHAIN_HASH: [u8; 32] = [11; 32]; - type GenesisConfig = ::Config; type GenesisInput = (); type ModuleExecutionConfig = (); @@ -131,10 +130,10 @@ macro_rules! generate_runtime_without_capabilities { fn endpoints(api_state: sov_modules_api::rest::ApiState) -> ::sov_modules_api::NodeEndpoints { use $crate::sov_rollup_apis::endpoints::dedup::{DeDupEndpoint, SovereignDeDupEndpoint}; use $crate::sov_rollup_apis::endpoints::schema::{SchemaEndpoint, StandardSchemaEndpoint}; - use $crate::sov_universal_wallet::schema::{ChainData, Schema}; - use ::sov_modules_api::macros::config_value; - use ::sov_modules_api::transaction::{Transaction, UnsignedTransaction}; + use $crate::sov_rollup_apis::endpoints::constants::ConstantsResponse; + use $crate::sov_rollup_apis::endpoints::constants::ConstantsEndpoint; use ::sov_modules_api::rest::HasRestApi; + use ::sov_modules_api::{CHAIN_ID, CHAIN_NAME}; let axum_router = Self::default().rest_api(api_state.clone()); // Provide an endpoint to return dedup information associated with addresses. @@ -142,33 +141,34 @@ macro_rules! generate_runtime_without_capabilities { let dedup_endpoint = SovereignDeDupEndpoint::new(api_state.clone()); let axum_router = axum_router.merge(dedup_endpoint.axum_router()); - let schema = Schema::of_rollup_types_with_chain_data::< - Transaction, - UnsignedTransaction, - ::Decodable, - S::Address, - >(ChainData { - chain_id: config_value!("CHAIN_ID"), - chain_name: config_value!("CHAIN_NAME").to_string(), - }) - .unwrap(); + let schema = get_runtime_schema::>().unwrap(); // StandardSchemaEndpoint resolves chain hash based on current height. // This ensures wallets get the correct chain hash during chain hash transitions. let schema_endpoint = StandardSchemaEndpoint::::new( &schema, - Self::CHAIN_HASH.into(), + schema.chain_hash().unwrap().into(), api_state.checkpoint_receiver(), ) .expect("Failed to initialize StandardSchemaEndpoint"); let axum_router = axum_router.merge(schema_endpoint.axum_router()); - let axum_router = axum_router.merge($crate::sov_rollup_apis::endpoints::constants::axum_router()); + + let constants_endpoint = ConstantsResponse { + chain_id: *CHAIN_ID, + chain_name: CHAIN_NAME.to_string(), + hyperlane_domain: config_value!("HYPERLANE_BRIDGE_DOMAIN"), + address_prefix: config_value!("ADDRESS_PREFIX"), + }; + let axum_router = axum_router.merge(constants_endpoint.axum_router()); ::sov_modules_api::NodeEndpoints { axum_router, jsonrpsee_module: get_rpc_methods(api_state), } } + fn chain_hash() -> [u8; 32] { + [11; 32] + } fn genesis_config(_input: &Self::GenesisInput) -> ::sov_modules_api::prelude::anyhow::Result { unimplemented!() diff --git a/crates/web3/src/rust.rs b/crates/web3/src/rust.rs index 471daed883..f3781062c7 100644 --- a/crates/web3/src/rust.rs +++ b/crates/web3/src/rust.rs @@ -35,7 +35,6 @@ //! parameters, this module provides better performance and compile-time guarantees. //! For language bindings or when generics are not available, use the `schema` module. -use sov_modules_api::capabilities::config_chain_id; use sov_modules_api::{CallMessage, CryptoSpec, RuntimeDiscriminant, UnmanagedRuntimeCall}; pub use sov_modules_api::capabilities::UniquenessData; @@ -57,6 +56,9 @@ pub enum TransactionBuilderError { pub trait ChainHash { /// Returns the 32-byte hash that uniquely identifies the chain. fn chain_hash() -> [u8; 32]; + + /// Returns the id of the chain. + fn chain_id() -> u64; } /// Default maximum priority fee in basis points (0). @@ -210,7 +212,7 @@ impl TransactionBui Ok(UnsignedTransaction::new( self.call, - config_chain_id(), + C::chain_id(), priority_fee, max_fee, uniqueness,