From 8be242a15c91b704358f4a43a4a17a0c69289d42 Mon Sep 17 00:00:00 2001 From: azurwastaken Date: Wed, 18 Sep 2024 10:12:38 +0200 Subject: [PATCH] feat: configurable chain config (#255) --- CHANGELOG.md | 1 + Cargo.lock | 32 ++ Cargo.toml | 1 + config.example.yaml | 62 +++ crates/client/db/Cargo.toml | 1 + crates/client/db/tests/common/mod.rs | 2 +- crates/client/db/tests/test_block.rs | 37 +- crates/client/db/tests/test_open.rs | 16 +- crates/client/devnet/Cargo.toml | 1 + crates/client/devnet/src/lib.rs | 18 +- crates/client/eth/src/l1_messaging.rs | 9 +- crates/client/eth/src/state_update.rs | 2 +- crates/client/rpc/Cargo.toml | 1 + crates/client/rpc/src/test_utils.rs | 5 +- crates/node/Cargo.toml | 4 + crates/node/src/cli/chain_config_overrides.rs | 85 +++ crates/node/src/cli/mod.rs | 47 +- crates/node/src/main.rs | 19 +- crates/primitives/chain_config/Cargo.toml | 7 + .../chain_config/presets/integration.yaml | 33 ++ .../chain_config/presets/mainnet.yaml | 33 ++ .../chain_config/presets/sepolia.yaml | 33 ++ .../primitives/chain_config/presets/test.yaml | 33 ++ .../chain_config/src/chain_config.rs | 496 +++++++++++++----- crates/primitives/utils/Cargo.toml | 3 +- crates/primitives/utils/src/lib.rs | 1 + crates/primitives/utils/src/tests_common.rs | 17 + crates/tests/Cargo.toml | 4 + crates/tests/src/lib.rs | 18 +- crates/tests/src/rpc/read.rs | 76 ++- 30 files changed, 883 insertions(+), 214 deletions(-) create mode 100644 config.example.yaml create mode 100644 crates/node/src/cli/chain_config_overrides.rs create mode 100644 crates/primitives/chain_config/presets/integration.yaml create mode 100644 crates/primitives/chain_config/presets/mainnet.yaml create mode 100644 crates/primitives/chain_config/presets/sepolia.yaml create mode 100644 crates/primitives/chain_config/presets/test.yaml create mode 100644 crates/primitives/utils/src/tests_common.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 486faa106..009eac1bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Next release +- feat: add config file and preset configure chain - refactor: change default chain id and add custom flag to override - fix: generate a fixed set of public and private keys for devnet - fix: defaulted l1 gas price in devnet mode diff --git a/Cargo.lock b/Cargo.lock index e20c8d198..06899d467 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5344,6 +5344,7 @@ dependencies = [ "alloy", "anyhow", "async-trait", + "blockifier", "chrono", "clap", "env_logger 0.11.3", @@ -5368,10 +5369,13 @@ dependencies = [ "mp-chain-config", "mp-convert", "mp-utils", + "primitive-types", "rand", "rayon", "reqwest 0.12.5", + "serde", "serde_json", + "starknet-core", "starknet-providers", "starknet_api", "thiserror", @@ -5441,6 +5445,7 @@ dependencies = [ "mp-utils", "rayon", "rocksdb", + "rstest 0.18.2", "serde", "starknet-core", "starknet-types-core", @@ -5470,6 +5475,7 @@ dependencies = [ "mp-receipt", "mp-state-update", "mp-transactions", + "mp-utils", "proptest", "proptest-derive", "rand", @@ -5490,6 +5496,7 @@ dependencies = [ "env_logger 0.11.3", "flate2", "lazy_static", + "mp-utils", "once_cell", "reqwest 0.12.5", "rstest 0.18.2", @@ -5624,6 +5631,7 @@ dependencies = [ "mp-receipt", "mp-state-update", "mp-transactions", + "mp-utils", "paste", "rstest 0.18.2", "serde_json", @@ -5773,11 +5781,15 @@ dependencies = [ name = "mp-chain-config" version = "0.7.0" dependencies = [ + "anyhow", "blockifier", "lazy_static", + "mp-utils", "primitive-types", + "rstest 0.18.2", "serde", "serde_json", + "serde_yaml", "starknet-types-core", "starknet_api", "thiserror", @@ -5879,6 +5891,7 @@ dependencies = [ "async-trait", "futures", "rayon", + "rstest 0.18.2", "tokio", ] @@ -7538,6 +7551,19 @@ dependencies = [ "syn 2.0.66", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap 2.2.6", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "serial_test" version = "3.1.1" @@ -8872,6 +8898,12 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "untrusted" version = "0.9.0" diff --git a/Cargo.toml b/Cargo.toml index 21bc02728..f3a94570c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -159,6 +159,7 @@ reqwest = { version = "0.12", features = ["json"] } rstest = "0.18" serde = { version = "1.0", default-features = false, features = ["std"] } serde_json = { version = "1.0", default-features = false, features = ["std"] } +serde_yaml = { version = "0.9.34" } thiserror = "1.0" tokio = { version = "1.34", features = ["signal"] } url = "2.4" diff --git a/config.example.yaml b/config.example.yaml new file mode 100644 index 000000000..720bd962c --- /dev/null +++ b/config.example.yaml @@ -0,0 +1,62 @@ +# Name of the blockchain network +chain_name: "Starknet Mainnet" + +# Unique identifier for the blockchain network +chain_id: "SN_MAIN" + +# Contract address of the token used to pay transaction fees on this network (STRK) +native_fee_token_address: "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d" + +# Contract address of the token used for fees on the parent chain (ETH) +parent_fee_token_address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7" + +# Paths to JSON files containing blockifier's constants for different versions +versioned_constants: + "0.13.0": "crates/primitives/chain_config/resources/versioned_constants_13_0.json" + "0.13.1": "crates/primitives/chain_config/resources/versioned_constants_13_1.json" + "0.13.1.1": "crates/primitives/chain_config/resources/versioned_constants_13_1_1.json" + "0.13.2": "crates/primitives/chain_config/resources/versioned_constants_13_2.json" + +# Address of the core contract on the L1 network that interacts with this L2 network +eth_core_contract_address: "0xc662c410C0ECf747543f5bA90660f6ABeBD9C8c4" + +# Most recent version supported +latest_protocol_version: "0.13.2" + +# Target time interval between blocks, in seconds +block_time: 360 + +# How often the pending block is updated, in seconds +pending_block_update_time: 2 + +# Settings for the transaction bouncer +bouncer_config: + block_max_capacity: + # Limits for various built-in operations (set to max uint64 value) + builtin_count: + add_mod: 18446744073709551615 + bitwise: 18446744073709551615 + ecdsa: 18446744073709551615 + ec_op: 18446744073709551615 + keccak: 18446744073709551615 + mul_mod: 18446744073709551615 + pedersen: 18446744073709551615 + poseidon: 18446744073709551615 + range_check: 18446744073709551615 + range_check96: 18446744073709551615 + # Maximum gas limit per block + gas: 5000000 + # Maximum number of steps per block + n_steps: 40000000 + # Maximum length of message segments + message_segment_length: 18446744073709551615 + # Maximum number of events per block + n_events: 18446744073709551615 + # Maximum size of state differences per block + state_diff_size: 131072 + +# Address of the sequencer (0x0 for a full node). +sequencer_address: "0x0" + +# Maximum nonce difference allowed for skipping validation of intermediate transactions +max_nonce_for_validation_skip: 2 diff --git a/crates/client/db/Cargo.toml b/crates/client/db/Cargo.toml index 9007f8e84..d5099ea7d 100644 --- a/crates/client/db/Cargo.toml +++ b/crates/client/db/Cargo.toml @@ -34,6 +34,7 @@ bincode = { workspace = true } log = { workspace = true, default-features = true } rayon = { workspace = true } rocksdb.workspace = true +rstest = { workspace = true } serde = { workspace = true } tempfile = { workspace = true, optional = true } thiserror = { workspace = true } diff --git a/crates/client/db/tests/common/mod.rs b/crates/client/db/tests/common/mod.rs index b90036874..dfcf65b78 100644 --- a/crates/client/db/tests/common/mod.rs +++ b/crates/client/db/tests/common/mod.rs @@ -4,6 +4,6 @@ use tempfile::TempDir; pub async fn temp_db() -> DatabaseService { let temp_dir = TempDir::new().unwrap(); - let chain_config = std::sync::Arc::new(ChainConfig::test_config()); + let chain_config = std::sync::Arc::new(ChainConfig::test_config().expect("failed to retrieve test chain config")); DatabaseService::new(temp_dir.path(), None, false, chain_config).await.unwrap() } diff --git a/crates/client/db/tests/test_block.rs b/crates/client/db/tests/test_block.rs index e0a14bd21..288132af4 100644 --- a/crates/client/db/tests/test_block.rs +++ b/crates/client/db/tests/test_block.rs @@ -1,5 +1,6 @@ mod common; -use common::temp_db; + +use common::*; use mc_db::db_block_id::DbBlockIdResolvable; use mc_db::{block_db::TxIndex, db_block_id::DbBlockId}; use mp_block::BlockId; @@ -17,17 +18,21 @@ use mp_transactions::{ DeployAccountTransactionV3, DeployTransaction, InvokeTransactionV0, InvokeTransactionV1, InvokeTransactionV3, L1HandlerTransaction, }; +use mp_utils::tests_common::*; +use rstest::*; use starknet_types_core::felt::Felt; +#[rstest] #[tokio::test] -async fn test_chain_info() { +async fn test_chain_info(_set_workdir: ()) { let db = temp_db().await; let chain_config = db.backend().chain_config(); - assert_eq!(chain_config.chain_id, ChainConfig::test_config().chain_id); + assert_eq!(chain_config.chain_id, ChainConfig::test_config().unwrap().chain_id); } +#[rstest] #[tokio::test] -async fn test_block_id() { +async fn test_block_id(_set_workdir: ()) { let db = temp_db().await; let backend = db.backend(); @@ -43,16 +48,18 @@ async fn test_block_id() { assert_eq!(backend.resolve_block_id(&DbBlockId::Pending).unwrap().unwrap(), DbBlockId::Pending); } +#[rstest] #[tokio::test] -async fn test_block_id_not_found() { +async fn test_block_id_not_found(_set_workdir: ()) { let db = temp_db().await; let backend = db.backend(); assert!(backend.resolve_block_id(&BlockId::Hash(Felt::from(0))).unwrap().is_none()); } +#[rstest] #[tokio::test] -async fn test_store_block() { +async fn test_store_block(_set_workdir: ()) { const BLOCK_ID_0: DbBlockId = DbBlockId::BlockN(0); let db = temp_db().await; @@ -74,8 +81,9 @@ async fn test_store_block() { assert_eq!(backend.get_block_state_diff(&BLOCK_ID_0).unwrap().unwrap(), state_diff); } +#[rstest] #[tokio::test] -async fn test_store_pending_block() { +async fn test_store_pending_block(_set_workdir: ()) { const BLOCK_ID_PENDING: DbBlockId = DbBlockId::Pending; let db = temp_db().await; @@ -95,8 +103,9 @@ async fn test_store_pending_block() { assert_eq!(backend.get_block_state_diff(&BLOCK_ID_PENDING).unwrap().unwrap(), state_diff); } +#[rstest] #[tokio::test] -async fn test_erase_pending_block() { +async fn test_erase_pending_block(_set_workdir: ()) { const BLOCK_ID_PENDING: DbBlockId = DbBlockId::Pending; let db = temp_db().await; @@ -126,8 +135,9 @@ async fn test_erase_pending_block() { assert_eq!(backend.get_block_state_diff(&BLOCK_ID_PENDING).unwrap().unwrap(), state_diff); } +#[rstest] #[tokio::test] -async fn test_store_latest_block() { +async fn test_store_latest_block(_set_workdir: ()) { let db = temp_db().await; let backend = db.backend(); @@ -139,8 +149,9 @@ async fn test_store_latest_block() { assert_eq!(backend.get_latest_block_n().unwrap().unwrap(), 1); } +#[rstest] #[tokio::test] -async fn test_latest_confirmed_block() { +async fn test_latest_confirmed_block(_set_workdir: ()) { let db = temp_db().await; let backend = db.backend(); @@ -151,8 +162,9 @@ async fn test_latest_confirmed_block() { assert_eq!(backend.get_l1_last_confirmed_block().unwrap().unwrap(), 0); } +#[rstest] #[tokio::test] -async fn test_store_block_transactions() { +async fn test_store_block_transactions(_set_workdir: ()) { let db = temp_db().await; let backend = db.backend(); @@ -166,8 +178,9 @@ async fn test_store_block_transactions() { assert_eq!(backend.find_tx_hash_block(&tx_hash_1).unwrap().unwrap(), (block, TxIndex(1))); } +#[rstest] #[tokio::test] -async fn test_store_block_transactions_pending() { +async fn test_store_block_transactions_pending(_set_workdir: ()) { let db = temp_db().await; let backend = db.backend(); diff --git a/crates/client/db/tests/test_open.rs b/crates/client/db/tests/test_open.rs index 9bee55bd4..2aed11bc7 100644 --- a/crates/client/db/tests/test_open.rs +++ b/crates/client/db/tests/test_open.rs @@ -1,21 +1,27 @@ mod common; -use common::temp_db; +use common::*; use mc_db::DatabaseService; use mp_chain_config::ChainConfig; +use mp_utils::tests_common::*; +use rstest::*; +#[rstest] #[tokio::test] -async fn test_open_db() { +async fn test_open_db(_set_workdir: ()) { temp_db().await; } +#[rstest] #[tokio::test] -async fn test_open_different_chain_id() { +async fn test_open_different_chain_id(_set_workdir: ()) { let temp_dir = tempfile::TempDir::new().unwrap(); { - let chain_config = std::sync::Arc::new(ChainConfig::starknet_integration()); + let chain_config = std::sync::Arc::new( + ChainConfig::starknet_integration().expect("failed to retrieve integration chain config"), + ); let _db = DatabaseService::new(temp_dir.path(), None, false, chain_config).await.unwrap(); } - let chain_config = std::sync::Arc::new(ChainConfig::test_config()); + let chain_config = std::sync::Arc::new(ChainConfig::test_config().expect("failed to retrieve test chain config")); assert!(DatabaseService::new(temp_dir.path(), None, false, chain_config).await.is_err()); } diff --git a/crates/client/devnet/Cargo.toml b/crates/client/devnet/Cargo.toml index c994c07da..f7af78965 100644 --- a/crates/client/devnet/Cargo.toml +++ b/crates/client/devnet/Cargo.toml @@ -36,6 +36,7 @@ mp-convert.workspace = true mp-receipt.workspace = true mp-state-update.workspace = true mp-transactions.workspace = true +mp-utils.workspace = true # Starknet blockifier.workspace = true diff --git a/crates/client/devnet/src/lib.rs b/crates/client/devnet/src/lib.rs index 886ee5ffe..a6fd54e4b 100644 --- a/crates/client/devnet/src/lib.rs +++ b/crates/client/devnet/src/lib.rs @@ -211,6 +211,7 @@ mod tests { use mp_receipt::{Event, ExecutionResult, FeePayment, InvokeTransactionReceipt, PriceUnit, TransactionReceipt}; use mp_transactions::broadcasted_to_blockifier; use mp_transactions::compute_hash::calculate_contract_address; + use mp_utils::tests_common::*; use rstest::{fixture, rstest}; use starknet_core::types::contract::SierraClass; use starknet_core::types::{ @@ -311,7 +312,7 @@ mod tests { let mut g = ChainGenesisDescription::base_config(); let contracts = g.add_devnet_contracts(10); - let chain_config = Arc::new(ChainConfig::test_config()); + let chain_config = Arc::new(ChainConfig::test_config().unwrap()); let block = g.build(&chain_config).unwrap(); let backend = MadaraBackend::open_for_testing(Arc::clone(&chain_config)); let importer = Arc::new(BlockImporter::new(Arc::clone(&backend))); @@ -351,8 +352,8 @@ mod tests { } #[rstest] - #[case("../../../cairo/target/dev/madara_contracts_TestContract.contract_class.json")] - fn test_erc_20_declare(mut chain: DevnetForTesting, #[case] contract_path: &str) { + #[case("./cairo/target/dev/madara_contracts_TestContract.contract_class.json")] + fn test_erc_20_declare(_set_workdir: (), mut chain: DevnetForTesting, #[case] contract_path: &str) { println!("{}", chain.contracts); let sender_address = &chain.contracts.0[0]; @@ -372,7 +373,7 @@ mod tests { nonce: Felt::ZERO, contract_class: Arc::new(flattened_class), resource_bounds: ResourceBoundsMapping { - l1_gas: ResourceBounds { max_amount: 60000, max_price_per_unit: 10000 }, + l1_gas: ResourceBounds { max_amount: 210000, max_price_per_unit: 10000 }, l2_gas: ResourceBounds { max_amount: 60000, max_price_per_unit: 10000 }, }, tip: 0, @@ -412,7 +413,7 @@ mod tests { } #[rstest] - fn test_account_deploy(mut chain: DevnetForTesting) { + fn test_account_deploy(_set_workdir: (), mut chain: DevnetForTesting) { println!("{}", chain.contracts); let key = SigningKey::from_random(); @@ -509,7 +510,12 @@ mod tests { #[case(24235u128, false)] #[case(9_999u128 * STRK_FRI_DECIMALS, false)] #[case(10_001u128 * STRK_FRI_DECIMALS, true)] - fn test_basic_transfer(mut chain: DevnetForTesting, #[case] transfer_amount: u128, #[case] expect_reverted: bool) { + fn test_basic_transfer( + _set_workdir: (), + mut chain: DevnetForTesting, + #[case] transfer_amount: u128, + #[case] expect_reverted: bool, + ) { println!("{}", chain.contracts); let sequencer_address = chain.backend.chain_config().sequencer_address.to_felt(); diff --git a/crates/client/eth/src/l1_messaging.rs b/crates/client/eth/src/l1_messaging.rs index 9a29077b0..5d458e223 100644 --- a/crates/client/eth/src/l1_messaging.rs +++ b/crates/client/eth/src/l1_messaging.rs @@ -231,6 +231,7 @@ mod l1_messaging_tests { use mc_db::DatabaseService; use mc_metrics::MetricsService; use mp_chain_config::ChainConfig; + use mp_utils::tests_common::*; use rstest::*; use starknet_api::core::Nonce; use tempfile::TempDir; @@ -334,7 +335,7 @@ mod l1_messaging_tests { println!("Anvil started and running at `{}`", anvil.endpoint()); // Set up chain info - let chain_config = Arc::new(ChainConfig::test_config()); + let chain_config = Arc::new(ChainConfig::test_config().unwrap()); // Set up database paths let temp_dir = TempDir::new().expect("issue while creating temporary directory"); @@ -385,7 +386,7 @@ mod l1_messaging_tests { #[rstest] #[traced_test] #[tokio::test] - async fn e2e_test_basic_workflow(#[future] setup_test_env: TestRunner) { + async fn e2e_test_basic_workflow(#[future] setup_test_env: TestRunner, _set_workdir: ()) { let TestRunner { chain_config, db_service: db, dummy_contract: contract, eth_client, anvil: _anvil } = setup_test_env.await; @@ -437,7 +438,7 @@ mod l1_messaging_tests { #[rstest] #[traced_test] #[tokio::test] - async fn e2e_test_already_processed_event(#[future] setup_test_env: TestRunner) { + async fn e2e_test_already_processed_event(#[future] setup_test_env: TestRunner, _set_workdir: ()) { let TestRunner { chain_config, db_service: db, dummy_contract: contract, eth_client, anvil: _anvil } = setup_test_env.await; @@ -484,7 +485,7 @@ mod l1_messaging_tests { #[rstest] #[traced_test] #[tokio::test] - async fn e2e_test_message_canceled(#[future] setup_test_env: TestRunner) { + async fn e2e_test_message_canceled(#[future] setup_test_env: TestRunner, _set_workdir: ()) { let TestRunner { chain_config, db_service: db, dummy_contract: contract, eth_client, anvil: _anvil } = setup_test_env.await; diff --git a/crates/client/eth/src/state_update.rs b/crates/client/eth/src/state_update.rs index 2ba24f104..0cb284bb4 100644 --- a/crates/client/eth/src/state_update.rs +++ b/crates/client/eth/src/state_update.rs @@ -155,7 +155,7 @@ mod eth_client_event_subscription_test { println!("Anvil started and running at `{}`", anvil.endpoint()); // Set up chain info - let chain_info = Arc::new(ChainConfig::test_config()); + let chain_info = Arc::new(ChainConfig::test_config().unwrap()); // Set up database paths let temp_dir = TempDir::new().expect("issue while creating temporary directory"); diff --git a/crates/client/rpc/Cargo.toml b/crates/client/rpc/Cargo.toml index a4241c513..168bc38bb 100644 --- a/crates/client/rpc/Cargo.toml +++ b/crates/client/rpc/Cargo.toml @@ -31,6 +31,7 @@ mp-convert = { workspace = true, default-features = true } mp-receipt = { workspace = true } mp-state-update = { workspace = true } mp-transactions = { workspace = true } +mp-utils = { workspace = true } # Starknet blockifier = { workspace = true, default-features = true } diff --git a/crates/client/rpc/src/test_utils.rs b/crates/client/rpc/src/test_utils.rs index db764c63a..c6373cc32 100644 --- a/crates/client/rpc/src/test_utils.rs +++ b/crates/client/rpc/src/test_utils.rs @@ -14,6 +14,7 @@ use mp_state_update::{ StorageEntry, }; use mp_transactions::{InvokeTransaction, InvokeTransactionV0, Transaction}; +use mp_utils::tests_common::*; use rstest::fixture; use starknet_core::types::{ BroadcastedDeclareTransaction, BroadcastedDeployAccountTransaction, BroadcastedInvokeTransaction, @@ -50,8 +51,8 @@ impl AddTransactionProvider for TestTransactionProvider { } #[fixture] -pub fn rpc_test_setup() -> (Arc, Starknet) { - let chain_config = Arc::new(ChainConfig::test_config()); +pub fn rpc_test_setup(_set_workdir: ()) -> (Arc, Starknet) { + let chain_config = Arc::new(ChainConfig::test_config().unwrap()); let backend = MadaraBackend::open_for_testing(chain_config.clone()); let rpc = Starknet::new(backend.clone(), chain_config.clone(), Arc::new(TestTransactionProvider)); (backend, rpc) diff --git a/crates/node/Cargo.toml b/crates/node/Cargo.toml index 46b16c71b..451e5d098 100644 --- a/crates/node/Cargo.toml +++ b/crates/node/Cargo.toml @@ -33,6 +33,8 @@ mp-convert = { workspace = true } mp-utils = { workspace = true } # Starknet +blockifier = { workspace = true } +starknet-core = { workspace = true } starknet-providers = { workspace = true } starknet_api = { workspace = true } @@ -51,9 +53,11 @@ hyper.workspace = true ip_network.workspace = true jsonrpsee.workspace = true log = { workspace = true } +primitive-types.workspace = true rand = { workspace = true } rayon.workspace = true reqwest = { workspace = true } +serde = { workspace = true, features = ["derive"] } serde_json.workspace = true thiserror.workspace = true tokio = { workspace = true } diff --git a/crates/node/src/cli/chain_config_overrides.rs b/crates/node/src/cli/chain_config_overrides.rs new file mode 100644 index 000000000..4034229eb --- /dev/null +++ b/crates/node/src/cli/chain_config_overrides.rs @@ -0,0 +1,85 @@ +use std::{str::FromStr, time::Duration}; + +use mp_block::H160; +use mp_chain_config::{ChainConfig, StarknetVersion}; +use starknet_api::{ + contract_address, + core::{ChainId, ContractAddress, PatriciaKey}, + felt, patricia_key, +}; + +/// Parameters used to override chain config. +#[derive(Clone, Debug, clap::Parser)] +pub struct ChainConfigOverrideParams { + //Overrideable args + #[arg(long, requires = "chain_config_override", value_name = "OVERRIDED CHAIN NAME")] + pub chain_name: Option, + #[arg(long, requires = "chain_config_override", value_name = "OVERRIDED CHAIN ID")] + pub chain_id: Option, + #[arg(long, requires = "chain_config_override", value_name = "OVERRIDED NATIVE FEE TOKEN")] + pub native_fee_token_address: Option, + #[arg(long, requires = "chain_config_override", value_name = "OVERRIDED PARENT FEE TOKEN")] + pub parent_fee_token_address: Option, + #[arg(long, requires = "chain_config_override", value_name = "OVERRIDED LATEST PROTOCOL VERSION")] + pub latest_protocol_version: Option, + #[arg(long, requires = "chain_config_override", value_name = "OVERRIDED BLOCK TIME")] + pub block_time: Option, + #[arg(long, requires = "chain_config_override", value_name = "OVERRIDED PENDING BLOCK UPDATE")] + pub pending_block_update_time: Option, + #[arg(long, requires = "chain_config_override", value_name = "OVERRIDED SEQUENCER ADDRESS")] + pub sequencer_address: Option, + #[arg(long, requires = "chain_config_override", value_name = "OVERRIDED MAX NONCE VALIDATION FOR SKIP")] + pub max_nonce_for_validation_skip: Option, + #[arg(long, requires = "chain_config_override", value_name = "OVERRIDED ETH CORE CONTRACT")] + pub eth_core_contract_address: Option, +} + +impl ChainConfigOverrideParams { + pub fn override_cfg(&self, mut chain_config: ChainConfig) -> ChainConfig { + let params = self.clone(); + + if let Some(name) = params.chain_name { + chain_config.chain_name = name; + } + + if let Some(id) = params.chain_id { + chain_config.chain_id = ChainId::from(id); + } + + if let Some(address) = params.native_fee_token_address { + chain_config.native_fee_token_address = contract_address!(address.as_str()); + } + + if let Some(address) = params.parent_fee_token_address { + chain_config.parent_fee_token_address = contract_address!(address.as_str()); + } + + if let Some(version) = params.latest_protocol_version { + chain_config.latest_protocol_version = + StarknetVersion::from_str(version.as_str()).expect("failed to retrieve version"); + } + + if let Some(time) = params.block_time { + chain_config.block_time = Duration::from_secs(time); + } + + if let Some(time) = self.pending_block_update_time { + chain_config.pending_block_update_time = Duration::from_secs(time); + } + + if let Some(address) = params.sequencer_address { + chain_config.sequencer_address = contract_address!(address.as_str()); + } + + if let Some(max_nonce) = params.max_nonce_for_validation_skip { + chain_config.max_nonce_for_validation_skip = max_nonce; + } + + if let Some(address) = params.eth_core_contract_address { + chain_config.eth_core_contract_address = + H160::from_str(address.as_str()).expect("failed to parse core contract"); + } + + chain_config + } +} diff --git a/crates/node/src/cli/mod.rs b/crates/node/src/cli/mod.rs index 86429e9e8..a0bc30de0 100644 --- a/crates/node/src/cli/mod.rs +++ b/crates/node/src/cli/mod.rs @@ -1,4 +1,5 @@ pub mod block_production; +pub mod chain_config_overrides; pub mod db; pub mod l1; pub mod prometheus; @@ -8,18 +9,22 @@ pub mod telemetry; use crate::cli::l1::L1SyncParams; pub use block_production::*; +pub use chain_config_overrides::*; pub use db::*; pub use prometheus::*; pub use rpc::*; pub use sync::*; pub use telemetry::*; +use clap::ArgGroup; use mp_chain_config::ChainConfig; +use std::path::PathBuf; use std::sync::Arc; use url::Url; -#[derive(Clone, Debug, clap::Parser)] /// Madara: High performance Starknet sequencer/full-node. +#[derive(Clone, Debug, clap::Parser)] +#[clap(group(ArgGroup::new("chain_config").args(["chain_config_path", "preset"]).required(true)))] pub struct RunCmd { /// The human-readable name for this node. /// It is used as the network node name. @@ -61,6 +66,22 @@ pub struct RunCmd { /// The network chain configuration. #[clap(long, short, default_value = "main")] pub network: NetworkType, + + /// Chain configuration file path. + #[clap(long, value_name = "CHAIN CONFIG FILE PATH")] + pub chain_config_path: Option, + + /// Use preset as chain Config + #[clap(long, value_name = "PRESET NAME")] + pub preset: Option, + + /// Allow to override some parameters present in preset or configuration file + #[clap(long, action = clap::ArgAction::SetTrue, value_name = "OVERRIDE CONFIG FLAG")] + pub chain_config_override: bool, + + #[allow(missing_docs)] + #[clap(flatten)] + pub chain_params: ChainConfigOverrideParams, } impl RunCmd { @@ -76,6 +97,21 @@ impl RunCmd { self.name.as_ref().expect("Name was just set") } + pub fn get_config(&self) -> anyhow::Result> { + let mut chain_config: ChainConfig = match &self.preset { + Some(preset_name) => ChainConfig::from_preset(preset_name.as_str())?, + None => { + ChainConfig::from_yaml(&self.chain_config_path.clone().expect("Failed to retrieve chain config path"))? + } + }; + + // Override stuff if flag is setted + if self.chain_config_override { + chain_config = self.chain_params.override_cfg(chain_config); + } + Ok(Arc::new(chain_config)) + } + pub fn is_authority(&self) -> bool { self.authority || self.block_production_params.devnet } @@ -107,15 +143,6 @@ impl NetworkType { } } - pub fn chain_config(&self) -> Arc { - match self { - NetworkType::Main => Arc::new(ChainConfig::starknet_mainnet()), - NetworkType::Test => Arc::new(ChainConfig::starknet_sepolia()), - NetworkType::Integration => Arc::new(ChainConfig::starknet_integration()), - NetworkType::Devnet => Arc::new(ChainConfig::dev_config()), - } - } - pub fn gateway(&self) -> Url { format!("{}/gateway", self.uri()).parse().expect("Invalid uri") } diff --git a/crates/node/src/main.rs b/crates/node/src/main.rs index bac666ea3..349c6f3d6 100644 --- a/crates/node/src/main.rs +++ b/crates/node/src/main.rs @@ -2,18 +2,16 @@ #![warn(missing_docs)] #![warn(clippy::unwrap_used)] +mod cli; +mod service; +mod util; + use std::sync::Arc; use anyhow::Context; use clap::Parser; use mc_block_import::BlockImporter; -mod cli; -mod service; -mod util; -use crate::cli::NetworkType; -use crate::service::L1SyncService; -use cli::RunCmd; use mc_db::DatabaseService; use mc_mempool::{GasPriceProvider, L1DataProvider, Mempool}; use mc_metrics::MetricsService; @@ -21,9 +19,13 @@ use mc_rpc::providers::{AddTransactionProvider, ForwardToProvider, MempoolAddTxP use mc_telemetry::{SysInfo, TelemetryService}; use mp_convert::ToFelt; use mp_utils::service::{Service, ServiceGroup}; -use service::{BlockProductionService, RpcService, SyncService}; + use starknet_providers::SequencerGatewayProvider; +use cli::{NetworkType, RunCmd}; +use service::L1SyncService; +use service::{BlockProductionService, RpcService, SyncService}; + const GREET_IMPL_NAME: &str = "Madara"; const GREET_SUPPORT_URL: &str = "https://github.com/madara-alliance/madara/issues"; @@ -34,7 +36,8 @@ async fn main() -> anyhow::Result<()> { crate::util::raise_fdlimit(); let mut run_cmd: RunCmd = RunCmd::parse(); - let chain_config = run_cmd.network.chain_config(); + + let chain_config = run_cmd.get_config()?; let node_name = run_cmd.node_name_or_provide().await.to_string(); let node_version = env!("DEOXYS_BUILD_VERSION"); diff --git a/crates/primitives/chain_config/Cargo.toml b/crates/primitives/chain_config/Cargo.toml index d93aac4fa..7771e903a 100644 --- a/crates/primitives/chain_config/Cargo.toml +++ b/crates/primitives/chain_config/Cargo.toml @@ -14,9 +14,16 @@ blockifier = { workspace = true } starknet-types-core = { workspace = true } starknet_api = { workspace = true } +# Madara + +mp-utils.workspace = true + # Other +anyhow = { workspace = true } lazy_static = { workspace = true } primitive-types.workspace = true +rstest = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } +serde_yaml = { workspace = true } thiserror.workspace = true diff --git a/crates/primitives/chain_config/presets/integration.yaml b/crates/primitives/chain_config/presets/integration.yaml new file mode 100644 index 000000000..463e9fc41 --- /dev/null +++ b/crates/primitives/chain_config/presets/integration.yaml @@ -0,0 +1,33 @@ +chain_name: "Starknet Sepolia" +chain_id: "SN_INTEGRATION_SEPOLIA" +native_fee_token_address: "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d" +parent_fee_token_address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7" +versioned_constants: + "0.13.0": "crates/primitives/chain_config/resources/versioned_constants_13_0.json" + "0.13.1": "crates/primitives/chain_config/resources/versioned_constants_13_1.json" + "0.13.1.1": "crates/primitives/chain_config/resources/versioned_constants_13_1_1.json" + "0.13.2": "crates/primitives/chain_config/resources/versioned_constants_13_2.json" +eth_core_contract_address: "0x4737c0c1B4D5b1A687B42610DdabEE781152359c" +latest_protocol_version: "0.13.2" +block_time: 360 +pending_block_update_time: 2 +bouncer_config: + block_max_capacity: + builtin_count: + add_mod: 18446744073709551615 + bitwise: 18446744073709551615 + ecdsa: 18446744073709551615 + ec_op: 18446744073709551615 + keccak: 18446744073709551615 + mul_mod: 18446744073709551615 + pedersen: 18446744073709551615 + poseidon: 18446744073709551615 + range_check: 18446744073709551615 + range_check96: 18446744073709551615 + gas: 5000000 + n_steps: 40000000 + message_segment_length: 18446744073709551615 + n_events: 18446744073709551615 + state_diff_size: 131072 +sequencer_address: "0x0" +max_nonce_for_validation_skip: 2 diff --git a/crates/primitives/chain_config/presets/mainnet.yaml b/crates/primitives/chain_config/presets/mainnet.yaml new file mode 100644 index 000000000..2d06f00b1 --- /dev/null +++ b/crates/primitives/chain_config/presets/mainnet.yaml @@ -0,0 +1,33 @@ +chain_name: "Starknet Mainnet" +chain_id: "SN_MAIN" +native_fee_token_address: "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d" +parent_fee_token_address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7" +versioned_constants: + "0.13.0": "crates/primitives/chain_config/resources/versioned_constants_13_0.json" + "0.13.1": "crates/primitives/chain_config/resources/versioned_constants_13_1.json" + "0.13.1.1": "crates/primitives/chain_config/resources/versioned_constants_13_1_1.json" + "0.13.2": "crates/primitives/chain_config/resources/versioned_constants_13_2.json" +eth_core_contract_address: "0xc662c410C0ECf747543f5bA90660f6ABeBD9C8c4" +latest_protocol_version: "0.13.2" +block_time: 360 +pending_block_update_time: 2 +bouncer_config: + block_max_capacity: + builtin_count: + add_mod: 18446744073709551615 + bitwise: 18446744073709551615 + ecdsa: 18446744073709551615 + ec_op: 18446744073709551615 + keccak: 18446744073709551615 + mul_mod: 18446744073709551615 + pedersen: 18446744073709551615 + poseidon: 18446744073709551615 + range_check: 18446744073709551615 + range_check96: 18446744073709551615 + gas: 5000000 + n_steps: 40000000 + message_segment_length: 18446744073709551615 + n_events: 18446744073709551615 + state_diff_size: 131072 +sequencer_address: "0x0" +max_nonce_for_validation_skip: 2 diff --git a/crates/primitives/chain_config/presets/sepolia.yaml b/crates/primitives/chain_config/presets/sepolia.yaml new file mode 100644 index 000000000..f5b9a3697 --- /dev/null +++ b/crates/primitives/chain_config/presets/sepolia.yaml @@ -0,0 +1,33 @@ +chain_name: "Starknet Sepolia" +chain_id: "SN_SEPOLIA" +native_fee_token_address: "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d" +parent_fee_token_address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7" +versioned_constants: + "0.13.0": "crates/primitives/chain_config/resources/versioned_constants_13_0.json" + "0.13.1": "crates/primitives/chain_config/resources/versioned_constants_13_1.json" + "0.13.1.1": "crates/primitives/chain_config/resources/versioned_constants_13_1_1.json" + "0.13.2": "crates/primitives/chain_config/resources/versioned_constants_13_2.json" +eth_core_contract_address: "0xE2Bb56ee936fd6433DC0F6e7e3b8365C906AA057" +latest_protocol_version: "0.13.2" +block_time: 360 +pending_block_update_time: 2 +bouncer_config: + block_max_capacity: + builtin_count: + add_mod: 18446744073709551615 + bitwise: 18446744073709551615 + ecdsa: 18446744073709551615 + ec_op: 18446744073709551615 + keccak: 18446744073709551615 + mul_mod: 18446744073709551615 + pedersen: 18446744073709551615 + poseidon: 18446744073709551615 + range_check: 18446744073709551615 + range_check96: 18446744073709551615 + gas: 5000000 + n_steps: 40000000 + message_segment_length: 18446744073709551615 + n_events: 18446744073709551615 + state_diff_size: 131072 +sequencer_address: "0x0" +max_nonce_for_validation_skip: 2 diff --git a/crates/primitives/chain_config/presets/test.yaml b/crates/primitives/chain_config/presets/test.yaml new file mode 100644 index 000000000..b39dffc88 --- /dev/null +++ b/crates/primitives/chain_config/presets/test.yaml @@ -0,0 +1,33 @@ +chain_name: "Test" +chain_id: "MADARA_TEST" +native_fee_token_address: "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d" +parent_fee_token_address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7" +versioned_constants: + "0.13.0": "crates/primitives/chain_config/resources/versioned_constants_13_0.json" + "0.13.1": "crates/primitives/chain_config/resources/versioned_constants_13_1.json" + "0.13.1.1": "crates/primitives/chain_config/resources/versioned_constants_13_1_1.json" + "0.13.2": "crates/primitives/chain_config/resources/versioned_constants_13_2.json" +eth_core_contract_address: "0xE2Bb56ee936fd6433DC0F6e7e3b8365C906AA057" +latest_protocol_version: "0.13.2" +block_time: 360 +pending_block_update_time: 2 +bouncer_config: + block_max_capacity: + builtin_count: + add_mod: 18446744073709551615 + bitwise: 18446744073709551615 + ecdsa: 18446744073709551615 + ec_op: 18446744073709551615 + keccak: 18446744073709551615 + mul_mod: 18446744073709551615 + pedersen: 18446744073709551615 + poseidon: 18446744073709551615 + range_check: 18446744073709551615 + range_check96: 18446744073709551615 + gas: 5000000 + n_steps: 40000000 + message_segment_length: 18446744073709551615 + n_events: 18446744073709551615 + state_diff_size: 131072 +sequencer_address: "0x123" +max_nonce_for_validation_skip: 2 diff --git a/crates/primitives/chain_config/src/chain_config.rs b/crates/primitives/chain_config/src/chain_config.rs index db13eb281..457171557 100644 --- a/crates/primitives/chain_config/src/chain_config.rs +++ b/crates/primitives/chain_config/src/chain_config.rs @@ -1,37 +1,138 @@ use crate::StarknetVersion; -use blockifier::{ - bouncer::{BouncerConfig, BouncerWeights, BuiltinCount}, - versioned_constants::VersionedConstants, -}; +use anyhow::{bail, Context}; +use blockifier::bouncer::BouncerWeights; +use blockifier::{bouncer::BouncerConfig, versioned_constants::VersionedConstants}; use primitive_types::H160; -use starknet_api::core::{ChainId, ContractAddress, PatriciaKey}; -use starknet_types_core::felt::Felt; -use std::{collections::BTreeMap, ops::Deref, time::Duration}; - -pub mod eth_core_contract_address { - pub const MAINNET: &str = "0xc662c410C0ECf747543f5bA90660f6ABeBD9C8c4"; - pub const SEPOLIA_TESTNET: &str = "0xE2Bb56ee936fd6433DC0F6e7e3b8365C906AA057"; - pub const SEPOLIA_INTEGRATION: &str = "0x4737c0c1B4D5b1A687B42610DdabEE781152359c"; +use serde::Deserialize; +use serde::Deserializer; +use starknet_api::core::{ChainId, ContractAddress}; +use std::str::FromStr; +use std::{ + collections::BTreeMap, + fs::{self, File}, + io::Read, + path::{Path, PathBuf}, + time::Duration, +}; + +#[derive(thiserror::Error, Debug)] +#[error("Unsupported protocol version: {0}")] +pub struct UnsupportedProtocolVersion(StarknetVersion); + +pub enum ChainPreset { + Mainnet, + Sepolia, + IntegrationSepolia, + Test, } -const BLOCKIFIER_VERSIONED_CONSTANTS_JSON_0_13_0: &[u8] = include_bytes!("../resources/versioned_constants_13_0.json"); -const BLOCKIFIER_VERSIONED_CONSTANTS_JSON_0_13_1: &[u8] = include_bytes!("../resources/versioned_constants_13_1.json"); -const BLOCKIFIER_VERSIONED_CONSTANTS_JSON_0_13_1_1: &[u8] = - include_bytes!("../resources/versioned_constants_13_1_1.json"); -const BLOCKIFIER_VERSIONED_CONSTANTS_JSON_0_13_2: &[u8] = include_bytes!("../resources/versioned_constants_13_2.json"); - -lazy_static::lazy_static! { - pub static ref BLOCKIFIER_VERSIONED_CONSTANTS_0_13_2: VersionedConstants = - serde_json::from_slice(BLOCKIFIER_VERSIONED_CONSTANTS_JSON_0_13_2).unwrap(); - pub static ref BLOCKIFIER_VERSIONED_CONSTANTS_0_13_1_1: VersionedConstants = - serde_json::from_slice(BLOCKIFIER_VERSIONED_CONSTANTS_JSON_0_13_1_1).unwrap(); - pub static ref BLOCKIFIER_VERSIONED_CONSTANTS_0_13_1: VersionedConstants = - serde_json::from_slice(BLOCKIFIER_VERSIONED_CONSTANTS_JSON_0_13_1).unwrap(); - pub static ref BLOCKIFIER_VERSIONED_CONSTANTS_0_13_0: VersionedConstants = - serde_json::from_slice(BLOCKIFIER_VERSIONED_CONSTANTS_JSON_0_13_0).unwrap(); +impl ChainPreset { + pub fn get_config(self) -> anyhow::Result { + match self { + ChainPreset::Mainnet => { + ChainConfig::from_yaml(Path::new("crates/primitives/chain_config/presets/mainnet.yaml")) + } + ChainPreset::Sepolia => { + ChainConfig::from_yaml(Path::new("crates/primitives/chain_config/presets/sepolia.yaml")) + } + ChainPreset::IntegrationSepolia => { + ChainConfig::from_yaml(Path::new("crates/primitives/chain_config/presets/integration.yaml")) + } + ChainPreset::Test => ChainConfig::from_yaml(Path::new("crates/primitives/chain_config/presets/test.yaml")), + } + } +} + +impl FromStr for ChainPreset { + type Err = anyhow::Error; + + fn from_str(preset_name: &str) -> Result { + match preset_name { + "mainnet" => Ok(ChainPreset::Mainnet), + "sepolia" => Ok(ChainPreset::Sepolia), + "integration-sepolia" => Ok(ChainPreset::IntegrationSepolia), + "test" => Ok(ChainPreset::Test), + _ => bail!("Failed to get preset {}", preset_name), + } + } } #[derive(Debug)] +pub struct ChainVersionedConstants(pub BTreeMap); + +impl From<[(StarknetVersion, VersionedConstants); N]> for ChainVersionedConstants { + fn from(arr: [(StarknetVersion, VersionedConstants); N]) -> Self { + ChainVersionedConstants(arr.into_iter().collect()) + } +} + +/// Replaces the versioned_constants files definition in the yaml by the content of the +/// jsons. +impl<'de> Deserialize<'de> for ChainVersionedConstants { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let file_paths: BTreeMap = Deserialize::deserialize(deserializer)?; + let mut result = BTreeMap::new(); + + for (version, path) in file_paths { + let mut file = File::open(Path::new(&path)) + .with_context(|| format!("Failed to open file: {}", path)) + .map_err(serde::de::Error::custom)?; + + let mut contents = String::new(); + file.read_to_string(&mut contents) + .with_context(|| format!("Failed to read contents of file: {}", path)) + .map_err(serde::de::Error::custom)?; + + let constants: VersionedConstants = serde_json::from_str(&contents) + .with_context(|| format!("Failed to parse JSON in file: {}", path)) + .map_err(serde::de::Error::custom)?; + + let parsed_version = version + .parse() + .with_context(|| format!("Failed to parse version string: {}", version)) + .map_err(serde::de::Error::custom)?; + + result.insert(parsed_version, constants); + } + + Ok(ChainVersionedConstants(result)) + } +} + +fn deserialize_starknet_version<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let s = String::deserialize(deserializer)?; + StarknetVersion::from_str(&s).map_err(serde::de::Error::custom) +} + +fn deserialize_duration<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let duration = u64::deserialize(deserializer)?; + Ok(Duration::from_secs(duration)) +} + +// TODO: this is workaround because BouncerConfig doesn't derive Deserialize in blockifier +pub fn deserialize_bouncer_config<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + #[derive(Deserialize)] + struct BouncerConfigHelper { + block_max_capacity: BouncerWeights, + } + + let helper = BouncerConfigHelper::deserialize(deserializer)?; + Ok(BouncerConfig { block_max_capacity: helper.block_max_capacity }) +} + +#[derive(Debug, Deserialize)] pub struct ChainConfig { /// Human readable chain name, for displaying to the console. pub chain_name: String, @@ -43,17 +144,21 @@ pub struct ChainConfig { pub parent_fee_token_address: ContractAddress, /// BTreeMap ensures order. - pub versioned_constants: BTreeMap, + pub versioned_constants: ChainVersionedConstants, + #[serde(deserialize_with = "deserialize_starknet_version")] pub latest_protocol_version: StarknetVersion, /// Only used for block production. + #[serde(deserialize_with = "deserialize_duration")] pub block_time: Duration, /// Only used for block production. /// Block time is divided into "ticks": everytime this duration elapses, the pending block is updated. + #[serde(deserialize_with = "deserialize_duration")] pub pending_block_update_time: Duration, /// The bouncer is in charge of limiting block sizes. This is where the max number of step per block, gas etc are. /// Only used for block production. + #[serde(deserialize_with = "deserialize_bouncer_config")] pub bouncer_config: BouncerConfig, /// Only used for block production. @@ -68,143 +173,260 @@ pub struct ChainConfig { pub eth_core_contract_address: H160, } -#[derive(thiserror::Error, Debug)] -#[error("Unsupported protocol version: {0}")] -pub struct UnsupportedProtocolVersion(StarknetVersion); +impl Default for ChainConfig { + fn default() -> Self { + ChainConfig::starknet_mainnet().expect("Invalid preset configuration for mainnet.") + } +} impl ChainConfig { - /// This is the number of pending ticks (see [`ChainConfig::pending_block_update_time`]) in a block. - pub fn n_pending_ticks_per_block(&self) -> usize { - (self.block_time.as_millis() / self.pending_block_update_time.as_millis()) as usize + pub fn from_preset(preset_name: &str) -> anyhow::Result { + ChainPreset::from_str(preset_name)?.get_config() } - pub fn exec_constants_by_protocol_version( - &self, - version: StarknetVersion, - ) -> Result { - for (k, constants) in self.versioned_constants.iter().rev() { - if k <= &version { - return Ok(constants.clone()); - } - } - Err(UnsupportedProtocolVersion(version)) + pub fn from_yaml(path: &Path) -> anyhow::Result { + let config_str = fs::read_to_string(path)?; + serde_yaml::from_str(&config_str).context("While deserializing chain config") } - pub fn starknet_mainnet() -> Self { + /// Returns the Chain Config preset for Starknet Mainnet. + pub fn starknet_mainnet() -> anyhow::Result { // Sources: // - https://docs.starknet.io/tools/important-addresses // - https://docs.starknet.io/tools/limits-and-triggers (bouncer & block times) // - state_diff_size is the blob size limit of ethereum // - pending_block_update_time: educated guess // - bouncer builtin_count, message_segment_length, n_events, state_diff_size are probably wrong + Self::from_yaml(&PathBuf::from_str("crates/primitives/chain_config/presets/mainnet.yaml")?) + } - Self { - chain_name: "Starknet Mainnet".into(), - chain_id: ChainId::Mainnet, - native_fee_token_address: ContractAddress( - PatriciaKey::try_from(Felt::from_hex_unchecked( - "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", - )) - .unwrap(), - ), - parent_fee_token_address: ContractAddress( - PatriciaKey::try_from(Felt::from_hex_unchecked( - "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - )) - .unwrap(), - ), - versioned_constants: [ - (StarknetVersion::V0_13_0, BLOCKIFIER_VERSIONED_CONSTANTS_0_13_0.deref().clone()), - (StarknetVersion::V0_13_1, BLOCKIFIER_VERSIONED_CONSTANTS_0_13_1.deref().clone()), - (StarknetVersion::V0_13_1_1, BLOCKIFIER_VERSIONED_CONSTANTS_0_13_1_1.deref().clone()), - (StarknetVersion::V0_13_2, VersionedConstants::latest_constants().clone()), - ] - .into(), - - eth_core_contract_address: eth_core_contract_address::MAINNET.parse().expect("parsing a constant"), - - latest_protocol_version: StarknetVersion::V0_13_2, - block_time: Duration::from_secs(6 * 60), - pending_block_update_time: Duration::from_secs(2), - - bouncer_config: BouncerConfig { - block_max_capacity: BouncerWeights { - builtin_count: BuiltinCount { - add_mod: usize::MAX, - bitwise: usize::MAX, - ecdsa: usize::MAX, - ec_op: usize::MAX, - keccak: usize::MAX, - mul_mod: usize::MAX, - pedersen: usize::MAX, - poseidon: usize::MAX, - range_check: usize::MAX, - range_check96: usize::MAX, - }, - gas: 5_000_000, - n_steps: 40_000_000, - message_segment_length: usize::MAX, - n_events: usize::MAX, - state_diff_size: 131072, - }, - }, - // We are not producing blocks for these chains. - sequencer_address: ContractAddress::default(), - max_nonce_for_validation_skip: 2, - } + /// Returns the Chain Config preset for Starknet Sepolia. + pub fn starknet_sepolia() -> anyhow::Result { + Self::from_yaml(&PathBuf::from_str("crates/primitives/chain_config/presets/sepolia.yaml")?) } - pub fn starknet_sepolia() -> Self { - Self { - chain_name: "Starknet Sepolia".into(), - chain_id: ChainId::Sepolia, - eth_core_contract_address: eth_core_contract_address::SEPOLIA_TESTNET.parse().expect("parsing a constant"), - ..Self::starknet_mainnet() - } + /// Returns the Chain Config preset for Starknet Integration. + pub fn starknet_integration() -> anyhow::Result { + Self::from_yaml(&PathBuf::from_str("crates/primitives/chain_config/presets/integration.yaml")?) } - pub fn starknet_integration() -> Self { - Self { - chain_name: "Starknet Sepolia Integration".into(), - chain_id: ChainId::IntegrationSepolia, - eth_core_contract_address: eth_core_contract_address::SEPOLIA_INTEGRATION - .parse() - .expect("parsing a constant"), - ..Self::starknet_mainnet() - } + /// Returns the Chain Config preset for our Madara tests. + pub fn test_config() -> anyhow::Result { + Self::from_yaml(&PathBuf::from_str("crates/primitives/chain_config/presets/test.yaml")?) } - pub fn dev_config() -> Self { - Self { - chain_name: "MADARA".into(), - chain_id: ChainId::Other("MADARA_DEVNET".into()), - // A random sequencer address for fee transfers to work in block production. - sequencer_address: Felt::from_hex_unchecked( - "0x211b748338b39fe8fa353819d457681aa50ac598a3db84cacdd6ece0a17e1f3", - ) - .try_into() - .unwrap(), - ..ChainConfig::starknet_sepolia() - } + /// This is the number of pending ticks (see [`ChainConfig::pending_block_update_time`]) in a block. + pub fn n_pending_ticks_per_block(&self) -> usize { + (self.block_time.as_millis() / self.pending_block_update_time.as_millis()) as usize } - pub fn test_config() -> Self { - Self { - chain_name: "Test".into(), - chain_id: ChainId::Other("MADARA_TEST".into()), - // We need a sequencer address for fee transfers to work in block production. - sequencer_address: Felt::from_hex_unchecked("0x123").try_into().unwrap(), - ..ChainConfig::starknet_sepolia() + pub fn exec_constants_by_protocol_version( + &self, + version: StarknetVersion, + ) -> Result { + for (k, constants) in self.versioned_constants.0.iter().rev() { + if k <= &version { + return Ok(constants.clone()); + } } + Err(UnsupportedProtocolVersion(version)) } } #[cfg(test)] mod tests { + use blockifier::{transaction::transaction_types::TransactionType, versioned_constants::ResourceCost}; + use mp_utils::tests_common::*; + use rstest::*; + use serde_json::Value; + use starknet_types_core::felt::Felt; + use super::*; - #[test] - fn test_exec_constants() { + #[rstest] + fn test_mainnet_from_yaml(_set_workdir: ()) { + let chain_config: ChainConfig = + ChainConfig::from_yaml(Path::new("crates/primitives/chain_config/presets/mainnet.yaml")) + .expect("failed to get cfg"); + + assert_eq!(chain_config.chain_name, "Starknet Mainnet"); + assert_eq!(chain_config.chain_id, ChainId::Mainnet); + + let native_fee_token_address = + Felt::from_hex("0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d").unwrap(); + let parent_fee_token_address = + Felt::from_hex("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7").unwrap(); + assert_eq!(chain_config.native_fee_token_address, ContractAddress::try_from(native_fee_token_address).unwrap()); + assert_eq!(chain_config.parent_fee_token_address, ContractAddress::try_from(parent_fee_token_address).unwrap()); + + // Check versioned constants + // Load and parse the JSON file + let json_content = fs::read_to_string("crates/primitives/chain_config/resources/versioned_constants_13_0.json") + .expect("Failed to read JSON file"); + let json: Value = serde_json::from_str(&json_content).expect("Failed to parse JSON"); + + // Get the VersionedConstants for version 0.13.0 + let constants = chain_config.versioned_constants.0.get(&StarknetVersion::from_str("0.13.0").unwrap()).unwrap(); + + // Check top-level fields + assert_eq!(constants.invoke_tx_max_n_steps, json["invoke_tx_max_n_steps"].as_u64().unwrap() as u32); + assert_eq!(constants.max_recursion_depth, json["max_recursion_depth"].as_u64().unwrap() as usize); + assert_eq!(constants.validate_max_n_steps, json["validate_max_n_steps"].as_u64().unwrap() as u32); + assert_eq!(constants.segment_arena_cells, json["segment_arena_cells"].as_bool().unwrap()); + + // Check L2ResourceGasCosts + let l2_costs = &constants.l2_resource_gas_costs; + assert_eq!(l2_costs.gas_per_data_felt, ResourceCost::from_integer(0)); + assert_eq!(l2_costs.event_key_factor, ResourceCost::from_integer(0)); + assert_eq!(l2_costs.gas_per_code_byte, ResourceCost::from_integer(0)); + + // Check OsConstants + let os_constants = &constants.os_constants; + assert_eq!(os_constants.gas_costs.step_gas_cost, json["os_constants"]["step_gas_cost"].as_u64().unwrap()); + assert_eq!( + os_constants.gas_costs.range_check_gas_cost, + json["os_constants"]["range_check_gas_cost"].as_u64().unwrap() + ); + // Add more checks for other gas costs... + + // Check ValidateRoundingConsts + assert_eq!(os_constants.validate_rounding_consts.validate_block_number_rounding, 1); + assert_eq!(os_constants.validate_rounding_consts.validate_timestamp_rounding, 1); + + // Check OsResources + let declare_tx_resources = constants.os_resources_for_tx_type(&TransactionType::Declare, 0); + assert!(declare_tx_resources.n_steps > 0); + + let invoke_tx_resources = constants.os_resources_for_tx_type(&TransactionType::InvokeFunction, 0); + assert!(invoke_tx_resources.n_steps > 0); + // Add more checks for other syscalls and their resources... + + // Check vm_resource_fee_cost using the public method + let vm_costs = constants.vm_resource_fee_cost(); + + // Verify specific resource costs + assert_eq!(vm_costs.get("n_steps").unwrap(), &ResourceCost::new(5, 1000)); + assert_eq!(vm_costs.get("pedersen_builtin").unwrap(), &ResourceCost::new(16, 100)); + assert_eq!(vm_costs.get("range_check_builtin").unwrap(), &ResourceCost::new(8, 100)); + assert_eq!(vm_costs.get("ecdsa_builtin").unwrap(), &ResourceCost::new(1024, 100)); + assert_eq!(vm_costs.get("bitwise_builtin").unwrap(), &ResourceCost::new(32, 100)); + assert_eq!(vm_costs.get("poseidon_builtin").unwrap(), &ResourceCost::new(16, 100)); + assert_eq!(vm_costs.get("ec_op_builtin").unwrap(), &ResourceCost::new(512, 100)); + assert_eq!(vm_costs.get("keccak_builtin").unwrap(), &ResourceCost::new(1024, 100)); + + assert_eq!(chain_config.latest_protocol_version, StarknetVersion::from_str("0.13.2").unwrap()); + assert_eq!(chain_config.block_time, Duration::from_secs(360)); + assert_eq!(chain_config.pending_block_update_time, Duration::from_secs(2)); + + // Check bouncer config + assert_eq!(chain_config.bouncer_config.block_max_capacity.gas, 5000000); + assert_eq!(chain_config.bouncer_config.block_max_capacity.n_steps, 40000000); + assert_eq!(chain_config.bouncer_config.block_max_capacity.state_diff_size, 131072); + assert_eq!(chain_config.bouncer_config.block_max_capacity.builtin_count.add_mod, 18446744073709551615); + + assert_eq!(chain_config.sequencer_address, ContractAddress::try_from(Felt::from_str("0x0").unwrap()).unwrap()); + assert_eq!(chain_config.max_nonce_for_validation_skip, 2); + assert_eq!( + chain_config.eth_core_contract_address, + H160::from_str("0xc662c410C0ECf747543f5bA90660f6ABeBD9C8c4").unwrap() + ); + } + + #[rstest] + fn test_from_preset(_set_workdir: ()) { + let chain_config: ChainConfig = ChainConfig::from_preset("mainnet").expect("failed to get cfg"); + + assert_eq!(chain_config.chain_name, "Starknet Mainnet"); + assert_eq!(chain_config.chain_id, ChainId::Mainnet); + + let native_fee_token_address = + Felt::from_hex("0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d").unwrap(); + let parent_fee_token_address = + Felt::from_hex("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7").unwrap(); + assert_eq!(chain_config.native_fee_token_address, ContractAddress::try_from(native_fee_token_address).unwrap()); + assert_eq!(chain_config.parent_fee_token_address, ContractAddress::try_from(parent_fee_token_address).unwrap()); + + // Check versioned constants + // Load and parse the JSON file + let json_content = fs::read_to_string("crates/primitives/chain_config/resources/versioned_constants_13_0.json") + .expect("Failed to read JSON file"); + let json: Value = serde_json::from_str(&json_content).expect("Failed to parse JSON"); + + // Get the VersionedConstants for version 0.13.0 + let constants = chain_config.versioned_constants.0.get(&StarknetVersion::from_str("0.13.0").unwrap()).unwrap(); + + // Check top-level fields + assert_eq!(constants.invoke_tx_max_n_steps, json["invoke_tx_max_n_steps"].as_u64().unwrap() as u32); + assert_eq!(constants.max_recursion_depth, json["max_recursion_depth"].as_u64().unwrap() as usize); + assert_eq!(constants.validate_max_n_steps, json["validate_max_n_steps"].as_u64().unwrap() as u32); + assert_eq!(constants.segment_arena_cells, json["segment_arena_cells"].as_bool().unwrap()); + + // Check L2ResourceGasCosts + let l2_costs = &constants.l2_resource_gas_costs; + assert_eq!(l2_costs.gas_per_data_felt, ResourceCost::from_integer(0)); + assert_eq!(l2_costs.event_key_factor, ResourceCost::from_integer(0)); + assert_eq!(l2_costs.gas_per_code_byte, ResourceCost::from_integer(0)); + + // Check OsConstants + let os_constants = &constants.os_constants; + assert_eq!(os_constants.gas_costs.step_gas_cost, json["os_constants"]["step_gas_cost"].as_u64().unwrap()); + assert_eq!( + os_constants.gas_costs.range_check_gas_cost, + json["os_constants"]["range_check_gas_cost"].as_u64().unwrap() + ); + // Add more checks for other gas costs... + + // Check ValidateRoundingConsts + assert_eq!(os_constants.validate_rounding_consts.validate_block_number_rounding, 1); + assert_eq!(os_constants.validate_rounding_consts.validate_timestamp_rounding, 1); + + // Check OsResources + let declare_tx_resources = constants.os_resources_for_tx_type(&TransactionType::Declare, 0); + assert!(declare_tx_resources.n_steps > 0); + + let invoke_tx_resources = constants.os_resources_for_tx_type(&TransactionType::InvokeFunction, 0); + assert!(invoke_tx_resources.n_steps > 0); + // Add more checks for other syscalls and their resources... + + // Check vm_resource_fee_cost using the public method + let vm_costs = constants.vm_resource_fee_cost(); + + // Verify specific resource costs + assert_eq!(vm_costs.get("n_steps").unwrap(), &ResourceCost::new(5, 1000)); + assert_eq!(vm_costs.get("pedersen_builtin").unwrap(), &ResourceCost::new(16, 100)); + assert_eq!(vm_costs.get("range_check_builtin").unwrap(), &ResourceCost::new(8, 100)); + assert_eq!(vm_costs.get("ecdsa_builtin").unwrap(), &ResourceCost::new(1024, 100)); + assert_eq!(vm_costs.get("bitwise_builtin").unwrap(), &ResourceCost::new(32, 100)); + assert_eq!(vm_costs.get("poseidon_builtin").unwrap(), &ResourceCost::new(16, 100)); + assert_eq!(vm_costs.get("ec_op_builtin").unwrap(), &ResourceCost::new(512, 100)); + assert_eq!(vm_costs.get("keccak_builtin").unwrap(), &ResourceCost::new(1024, 100)); + + // Check EventLimits + let event_limits = &constants.tx_event_limits; + assert_eq!(event_limits.max_data_length, usize::MAX); + assert_eq!(event_limits.max_keys_length, usize::MAX); + assert_eq!(event_limits.max_n_emitted_events, usize::MAX); + + assert_eq!(chain_config.latest_protocol_version, StarknetVersion::from_str("0.13.2").unwrap()); + assert_eq!(chain_config.block_time, Duration::from_secs(360)); + assert_eq!(chain_config.pending_block_update_time, Duration::from_secs(2)); + + // Check bouncer config + assert_eq!(chain_config.bouncer_config.block_max_capacity.gas, 5000000); + assert_eq!(chain_config.bouncer_config.block_max_capacity.n_steps, 40000000); + assert_eq!(chain_config.bouncer_config.block_max_capacity.state_diff_size, 131072); + assert_eq!(chain_config.bouncer_config.block_max_capacity.builtin_count.add_mod, 18446744073709551615); + + assert_eq!(chain_config.sequencer_address, ContractAddress::try_from(Felt::from_str("0x0").unwrap()).unwrap()); + assert_eq!(chain_config.max_nonce_for_validation_skip, 2); + assert_eq!( + chain_config.eth_core_contract_address, + H160::from_str("0xc662c410C0ECf747543f5bA90660f6ABeBD9C8c4").unwrap() + ); + } + + #[rstest] + fn test_exec_constants(_set_workdir: ()) { let chain_config = ChainConfig { versioned_constants: [ (StarknetVersion::new(0, 1, 5, 0), { @@ -219,7 +441,7 @@ mod tests { }), ] .into(), - ..ChainConfig::test_config() + ..ChainConfig::test_config().unwrap() }; assert_eq!( diff --git a/crates/primitives/utils/Cargo.toml b/crates/primitives/utils/Cargo.toml index 096bb97a4..9d524828d 100644 --- a/crates/primitives/utils/Cargo.toml +++ b/crates/primitives/utils/Cargo.toml @@ -13,9 +13,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] -# Orher +# Other anyhow.workspace = true async-trait.workspace = true futures.workspace = true rayon.workspace = true +rstest = { workspace = true } tokio = { workspace = true, features = ["signal"] } diff --git a/crates/primitives/utils/src/lib.rs b/crates/primitives/utils/src/lib.rs index 74b3f8f3f..41b305171 100644 --- a/crates/primitives/utils/src/lib.rs +++ b/crates/primitives/utils/src/lib.rs @@ -1,6 +1,7 @@ #![allow(clippy::new_without_default)] pub mod service; +pub mod tests_common; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::{Duration, Instant}; diff --git a/crates/primitives/utils/src/tests_common.rs b/crates/primitives/utils/src/tests_common.rs new file mode 100644 index 000000000..a8211943c --- /dev/null +++ b/crates/primitives/utils/src/tests_common.rs @@ -0,0 +1,17 @@ +use rstest::fixture; +use std::{env, path::PathBuf}; + +#[fixture] +pub fn set_workdir() { + let output = std::process::Command::new("cargo") + .arg("locate-project") + .arg("--workspace") + .arg("--message-format=plain") + .output() + .expect("Failed to execute command"); + + let cargo_toml_path = String::from_utf8(output.stdout).expect("Invalid UTF-8"); + let project_root = PathBuf::from(cargo_toml_path.trim()).parent().unwrap().to_path_buf(); + + env::set_current_dir(&project_root).expect("Failed to set working directory"); +} diff --git a/crates/tests/Cargo.toml b/crates/tests/Cargo.toml index 3f9e99397..899a11307 100644 --- a/crates/tests/Cargo.toml +++ b/crates/tests/Cargo.toml @@ -9,6 +9,10 @@ license.workspace = true [dependencies] +# Madara + +mp-utils.workspace = true + anyhow.workspace = true env_logger.workspace = true flate2 = "1.0.30" diff --git a/crates/tests/src/lib.rs b/crates/tests/src/lib.rs index 115be3594..76ffeebd3 100644 --- a/crates/tests/src/lib.rs +++ b/crates/tests/src/lib.rs @@ -170,7 +170,7 @@ impl MadaraCmdBuilder { } pub fn run(self) -> MadaraCmd { - let target_bin = option_env!("COVERAGE_BIN").unwrap_or("../../target/debug/madara"); + let target_bin = option_env!("COVERAGE_BIN").unwrap_or("./target/debug/madara"); let target_bin = PathBuf::from_str(target_bin).expect("target bin is not a path"); if !target_bin.exists() { panic!("No binary to run: {:?}", target_bin) @@ -201,8 +201,10 @@ impl MadaraCmdBuilder { } } +#[allow(unused_imports)] +use mp_utils::tests_common::set_workdir; #[rstest] -fn madara_help_shows() { +fn madara_help_shows(_set_workdir: ()) { let _ = env_logger::builder().is_test(true).try_init(); let output = MadaraCmdBuilder::new().args(["--help"]).run().wait_with_output(); assert!(output.status.success()); @@ -212,12 +214,20 @@ fn madara_help_shows() { #[rstest] #[tokio::test] -async fn madara_can_sync_a_few_blocks() { +async fn madara_can_sync_a_few_blocks(_set_workdir: ()) { use starknet_core::types::{BlockHashAndNumber, Felt}; let _ = env_logger::builder().is_test(true).try_init(); let mut node = MadaraCmdBuilder::new() - .args(["--network", "sepolia", "--no-sync-polling", "--n-blocks-to-sync", "20", "--no-l1-sync"]) + .args([ + "--network", + "sepolia", + "--no-sync-polling", + "--n-blocks-to-sync", + "20", + "--no-l1-sync", + "--preset=sepolia", + ]) .run(); node.wait_for_ready().await; node.wait_for_sync_to(19).await; diff --git a/crates/tests/src/rpc/read.rs b/crates/tests/src/rpc/read.rs index 146539d1f..3a17b376f 100644 --- a/crates/tests/src/rpc/read.rs +++ b/crates/tests/src/rpc/read.rs @@ -4,8 +4,10 @@ #[cfg(test)] mod test_rpc_read_calls { use once_cell::sync::Lazy; + use rstest::rstest; use std::any::Any; + use crate::set_workdir; use crate::{MadaraCmd, MadaraCmdBuilder}; use flate2::read::GzDecoder; use starknet::macros::felt; @@ -35,7 +37,15 @@ mod test_rpc_read_calls { async fn setup_madara() -> MadaraCmd { let mut madara = MadaraCmdBuilder::new() - .args(["--network", "sepolia", "--no-sync-polling", "--n-blocks-to-sync", "20", "--no-l1-sync"]) + .args([ + "--network", + "sepolia", + "--no-sync-polling", + "--n-blocks-to-sync", + "20", + "--no-l1-sync", + "--preset=sepolia", + ]) .run(); madara.wait_for_ready().await; @@ -62,8 +72,9 @@ mod test_rpc_read_calls { /// "id": 1 /// }' /// ``` + #[rstest] #[tokio::test] - async fn test_block_hash_and_number_works() { + async fn test_block_hash_and_number_works(_set_workdir: ()) { let madara = get_shared_state().await; let json_client = JsonRpcClient::new(HttpTransport::new(madara.rpc_url.clone())); let result = { json_client.block_hash_and_number().await.unwrap() }; @@ -95,8 +106,9 @@ mod test_rpc_read_calls { /// "id": 1 /// }' /// ``` + #[rstest] #[tokio::test] - async fn test_get_block_txn_count_works() { + async fn test_get_block_txn_count_works(_set_workdir: ()) { let madara = get_shared_state().await; let json_client = JsonRpcClient::new(HttpTransport::new(madara.rpc_url.clone())); let result = { json_client.get_block_transaction_count(BlockId::Number(2)).await.unwrap() }; @@ -121,8 +133,9 @@ mod test_rpc_read_calls { /// "id": 1 /// }' /// ``` + #[rstest] #[tokio::test] - async fn test_get_block_txn_with_receipts_works() { + async fn test_get_block_txn_with_receipts_works(_set_workdir: ()) { let madara = get_shared_state().await; let json_client = JsonRpcClient::new(HttpTransport::new(madara.rpc_url.clone())); let block = { json_client.get_block_with_receipts(BlockId::Number(2)).await.unwrap() }; @@ -197,8 +210,9 @@ mod test_rpc_read_calls { /// "id": 1 /// }' /// ``` + #[rstest] #[tokio::test] - async fn test_get_block_txn_with_tx_hashes_works() { + async fn test_get_block_txn_with_tx_hashes_works(_set_workdir: ()) { let madara = get_shared_state().await; let json_client = JsonRpcClient::new(HttpTransport::new(madara.rpc_url.clone())); let block = { json_client.get_block_with_tx_hashes(BlockId::Number(2)).await.unwrap() }; @@ -238,8 +252,9 @@ mod test_rpc_read_calls { /// "id": 1 /// }' /// ``` + #[rstest] #[tokio::test] - async fn test_get_block_txn_with_tx_works() { + async fn test_get_block_txn_with_tx_works(_set_workdir: ()) { let madara = get_shared_state().await; let json_client = JsonRpcClient::new(HttpTransport::new(madara.rpc_url.clone())); let block = json_client.get_block_with_txs(BlockId::Number(2)).await.unwrap(); @@ -286,8 +301,9 @@ mod test_rpc_read_calls { /// "id": 1 /// }' /// ``` + #[rstest] #[tokio::test] - async fn test_get_class_hash_at_works() { + async fn test_get_class_hash_at_works(_set_workdir: ()) { let madara = get_shared_state().await; let json_client = JsonRpcClient::new(HttpTransport::new(madara.rpc_url.clone())); let class_hash = { @@ -323,8 +339,9 @@ mod test_rpc_read_calls { /// "id": 1 /// }' /// ``` + #[rstest] #[tokio::test] - async fn test_get_nonce_works() { + async fn test_get_nonce_works(_set_workdir: ()) { let madara = get_shared_state().await; let json_client = JsonRpcClient::new(HttpTransport::new(madara.rpc_url.clone())); let nonce = { @@ -360,8 +377,9 @@ mod test_rpc_read_calls { /// "id": 1 /// }' /// ``` + #[rstest] #[tokio::test] - async fn test_get_txn_by_block_id_and_index_works() { + async fn test_get_txn_by_block_id_and_index_works(_set_workdir: ()) { let madara = get_shared_state().await; let json_client = JsonRpcClient::new(HttpTransport::new(madara.rpc_url.clone())); let txn = { json_client.get_transaction_by_block_id_and_index(BlockId::Number(16), 1).await.unwrap() }; @@ -398,8 +416,9 @@ mod test_rpc_read_calls { /// "id": 1 /// }' /// ``` + #[rstest] #[tokio::test] - async fn test_get_txn_by_hash_works() { + async fn test_get_txn_by_hash_works(_set_workdir: ()) { let madara = get_shared_state().await; let json_client = JsonRpcClient::new(HttpTransport::new(madara.rpc_url.clone())); let txn = { @@ -441,8 +460,9 @@ mod test_rpc_read_calls { /// "id": 1 /// }' /// ``` + #[rstest] #[tokio::test] - async fn test_get_txn_receipt_works() { + async fn test_get_txn_receipt_works(_set_workdir: ()) { let madara = get_shared_state().await; let json_client = JsonRpcClient::new(HttpTransport::new(madara.rpc_url.clone())); let txn_receipt = { @@ -509,8 +529,9 @@ mod test_rpc_read_calls { /// verify the state root. /// /// Hence, all the txn would be marked as AcceptedOnL2. + #[rstest] #[tokio::test] - async fn test_get_txn_status_works() { + async fn test_get_txn_status_works(_set_workdir: ()) { let madara = get_shared_state().await; let json_client = JsonRpcClient::new(HttpTransport::new(madara.rpc_url.clone())); let txn_status = { @@ -544,8 +565,9 @@ mod test_rpc_read_calls { /// "id": 1 /// }' /// ``` + #[rstest] #[tokio::test] - async fn test_get_storage_at_works() { + async fn test_get_storage_at_works(_set_workdir: ()) { let madara = get_shared_state().await; let json_client = JsonRpcClient::new(HttpTransport::new(madara.rpc_url.clone())); let storage_response = { @@ -581,8 +603,9 @@ mod test_rpc_read_calls { /// "id": 1 /// }' /// ``` + #[rstest] #[tokio::test] - async fn test_get_state_update_works() { + async fn test_get_state_update_works(_set_workdir: ()) { let madara = get_shared_state().await; let json_client = JsonRpcClient::new(HttpTransport::new(madara.rpc_url.clone())); let state_update = { json_client.get_state_update(BlockId::Number(13)).await.unwrap() }; @@ -660,8 +683,9 @@ mod test_rpc_read_calls { /// /// In here we are testing the event data apart from continuation token and checking type for /// the continuation token. + #[rstest] #[tokio::test] - async fn test_get_events_works() { + async fn test_get_events_works(_set_workdir: ()) { let madara = get_shared_state().await; let json_client = JsonRpcClient::new(HttpTransport::new(madara.rpc_url.clone())); let events = { @@ -738,8 +762,9 @@ mod test_rpc_read_calls { /// "id": 1 /// }' /// ``` + #[rstest] #[tokio::test] - async fn test_get_events_with_continuation_token_works() { + async fn test_get_events_with_continuation_token_works(_set_workdir: ()) { let madara = get_shared_state().await; let json_client = JsonRpcClient::new(HttpTransport::new(madara.rpc_url.clone())); let events = { @@ -828,8 +853,9 @@ mod test_rpc_read_calls { /// Note: The test is ignored as of now because madara support the transaction with starknet version >= 0.13.0 /// and ideally for the node will call the sequencer to get the result of the transaction for older starknet version. #[ignore] + #[rstest] #[tokio::test] - async fn test_call_works() { + async fn test_call_works(_set_workdir: ()) { let madara = get_shared_state().await; let json_client = JsonRpcClient::new(HttpTransport::new(madara.rpc_url.clone())); let call_response = { @@ -900,8 +926,9 @@ mod test_rpc_read_calls { /// with the decompressed program we get from the madara response. /// /// Along with that we are also checking for abi and the entry points. + #[rstest] #[tokio::test] - async fn test_get_class_works() { + async fn test_get_class_works(_set_workdir: ()) { let madara = get_shared_state().await; let json_client = JsonRpcClient::new(HttpTransport::new(madara.rpc_url.clone())); let contract_class = { @@ -938,8 +965,9 @@ mod test_rpc_read_calls { /// ``` /// /// Note: The program has been compressed using the same script mentioned in the above test case. + #[rstest] #[tokio::test] - async fn test_get_class_at_works() { + async fn test_get_class_at_works(_set_workdir: ()) { let madara = get_shared_state().await; let json_client = JsonRpcClient::new(HttpTransport::new(madara.rpc_url.clone())); let contract_class = { @@ -1001,8 +1029,9 @@ mod test_rpc_read_calls { /// Note: The test is ignored as of now because madara support the transaction with starknet version >= 0.13.0 /// and ideally for the node will call the sequencer to get the result of the transaction for older starknet version. #[ignore] + #[rstest] #[tokio::test] - async fn test_estimate_fee_works() { + async fn test_estimate_fee_works(_set_workdir: ()) { let madara = get_shared_state().await; let json_client = JsonRpcClient::new(HttpTransport::new(madara.rpc_url.clone())); let call_response = { @@ -1078,8 +1107,9 @@ mod test_rpc_read_calls { /// Note: The test is ignored as of now because madara support the transaction with starknet version >= 0.13.0 /// and ideally for the node will call the sequencer to get the result of the transaction for older starknet version. #[ignore] + #[rstest] #[tokio::test] - async fn test_estimate_message_fee_works() { + async fn test_estimate_message_fee_works(_set_workdir: ()) { let madara = get_shared_state().await; let json_client = JsonRpcClient::new(HttpTransport::new(madara.rpc_url.clone())); let call_response = { @@ -1128,12 +1158,12 @@ mod test_rpc_read_calls { let decompressed_program = decompress_to_string(contract_program.unwrap()); - let mut class_program_file = File::open("src/rpc/test_utils/class_program.txt").unwrap(); + let mut class_program_file = File::open("crates/tests/src/rpc/test_utils/class_program.txt").unwrap(); let mut original_program = String::new(); class_program_file.read_to_string(&mut original_program).expect("issue while reading the file"); - let contract_class_file = File::open("src/rpc/test_utils/contract_class.json").unwrap(); + let contract_class_file = File::open("crates/tests/src/rpc/test_utils/contract_class.json").unwrap(); let reader = BufReader::new(contract_class_file); let expected_contract_class: ContractClass = serde_json::from_reader(reader).unwrap();