diff --git a/.gitignore b/.gitignore index 958ed6ff..92e41e82 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ target/ book/ index.html tmp -.vscode \ No newline at end of file +.vscode +data diff --git a/Cargo.lock b/Cargo.lock index 3044ff93..d5d80038 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -395,6 +395,9 @@ dependencies = [ "clap", "dotenvy", "execute", + "serde", + "serde_json", + "tempfile", "toml", "tracing", "tracing-subscriber", @@ -439,7 +442,7 @@ dependencies = [ "iana-time-zone", "num-traits", "serde", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -2554,7 +2557,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -3723,14 +3726,15 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.10.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", "fastrand", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4377,7 +4381,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -4395,7 +4399,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -4415,18 +4428,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -4437,9 +4450,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -4449,9 +4462,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -4461,15 +4474,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -4479,9 +4492,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -4491,9 +4504,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -4503,9 +4516,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -4515,9 +4528,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" diff --git a/config/example-config.toml b/config/example-config.toml index e7207861..1c41c045 100644 --- a/config/example-config.toml +++ b/config/example-config.toml @@ -1,85 +1,101 @@ ForkUpgradeBatchNumber = 0 ForkUpgradeNewForkId = 0 +[Common] +IsValidiumMode = true +ContractVersions = "banana" + +[Etherman] +URL = "http://el-1-geth-lighthouse:8545" + [Log] Environment = "development" # "production" or "development" -Level = "info" +Level = "debug" Outputs = ["stderr"] [SequenceSender] -IsValidiumMode = false WaitPeriodSendSequence = "15s" LastBatchVirtualizationTimeMaxWaitPeriod = "10s" -L1BlockTimestampMargin = "30s" MaxTxSizeForL1 = 131072 -L2Coinbase = "0xfa3b44587990f97ba8b6ba7e230a5f0e95d14b3d" -PrivateKey = {Path = "./test/sequencer.keystore", Password = "testonly"} -SequencesTxFileName = "sequencesender.json" +L2Coinbase = "0x5b06837A43bdC3dD9F114558DAf4B26ed49842Ed" +PrivateKey = {Path = "/etc/cdk/sequencer.keystore", Password = "pSnv6Dh5s9ahuzGzH9RoCDrKAMddaX3m"} +SequencesTxFileName = "/data/sequencesender.json" GasOffset = 80000 WaitPeriodPurgeTxFile = "15m" MaxPendingTx = 1 +MaxBatchesForL1 = 300 +BlockFinality="SafeBlock" # TODO: should be finalized but it breaks :) +SanityCheckRPCURL = "" [SequenceSender.StreamClient] - Server = "127.0.0.1:6900" + Server = "cdk-erigon-sequencer-001:6900" [SequenceSender.EthTxManager] FrequencyToMonitorTxs = "1s" WaitTxToBeMined = "2m" - GetReceiptMaxTime = "250ms" - GetReceiptWaitInterval = "1s" + ConsolidationL1ConfirmationBlocks = 5 + FinalizedStatusL1NumberOfBlocks = 10 + WaitReceiptMaxTime = "250ms" + WaitReceiptCheckInterval = "8s" PrivateKeys = [ - {Path = "./test/sequencer.keystore", Password = "testonly"}, + {Path = "/etc/cdk/sequencer.keystore", Password = "pSnv6Dh5s9ahuzGzH9RoCDrKAMddaX3m"}, ] ForcedGas = 0 GasPriceMarginFactor = 1 MaxGasPriceLimit = 0 - PersistenceFilename = "ethtxmanager.json" - ReadPendingL1Txs = false - SafeStatusL1NumberOfBlocks = 0 - FinalizedStatusL1NumberOfBlocks = 0 - [SequenceSender.EthTxManager.Etherman] - URL = "http://127.0.0.1:32771" - MultiGasProvider = false - L1ChainID = 1337 + PersistenceFilename = "/data/ethtxmanager.json" + [SequenceSender.EthTxManager.Etherman] + URL = "http://el-1-geth-lighthouse:8545" + L1ChainID = 271828 + HTTPHeaders = [] + [Aggregator] -Host = "0.0.0.0" -Port = 50081 -RetryTime = "5s" -VerifyProofInterval = "10s" -TxProfitabilityCheckerType = "acceptall" -TxProfitabilityMinReward = "1.1" -ProofStatePollingInterval = "5s" -SenderAddress = "" -CleanupLockedProofsInterval = "2m" -GeneratingProofCleanupThreshold = "10m" -ForkId = 9 -GasOffset = 0 -WitnessURL = "localhost:8123" -UseL1BatchData = true -UseFullWitness = false -SettlementBackend = "l1" -AggLayerTxTimeout = "5m" -AggLayerURL = "" -SequencerPrivateKey = {} + Host = "0.0.0.0" + Port = 50081 + RetryTime = "30s" + VerifyProofInterval = "30s" + ProofStatePollingInterval = "5s" + TxProfitabilityCheckerType = "acceptall" + TxProfitabilityMinReward = "1.1" + IntervalAfterWhichBatchConsolidateAnyway = "0s" + ChainID = 10101 + ForkId = 12 + CleanupLockedProofsInterval = "2m0s" + GeneratingProofCleanupThreshold = "10m" + GasOffset = 150000 + WitnessURL = "http://cdk-erigon-node-001:8123" + + SenderAddress = "0x351e560852ee001d5D19b5912a269F849f59479a" + SequencerPrivateKey = {Path = "/etc/cdk/sequencer.keystore", Password = "pSnv6Dh5s9ahuzGzH9RoCDrKAMddaX3m"} + SettlementBackend = "agglayer" + AggLayerTxTimeout = "600s" + + AggLayerURL = "http://zkevm-agglayer-001:4444" + + + UseL1BatchData = true + UseFullWitness = false + MaxWitnessRetrievalWorkers = 2 + SyncModeOnlyEnabled = false [Aggregator.DB] Name = "aggregator_db" User = "aggregator_user" - Password = "master_password" - Host = "localhost" - Port = "32780" - EnableLog = false + Password = "redacted" + Host = "postgres-001" + Port = "5432" + EnableLog = false MaxConns = 200 [Aggregator.Log] Environment = "development" # "production" or "development" Level = "info" Outputs = ["stderr"] [Aggregator.StreamClient] - Server = "localhost:6900" + Server = "cdk-erigon-sequencer-001:6900" [Aggregator.EthTxManager] FrequencyToMonitorTxs = "1s" WaitTxToBeMined = "2m" - GetReceiptMaxTime = "250ms" - GetReceiptWaitInterval = "1s" + WaitReceiptMaxTime = "250ms" + WaitReceiptCheckInterval = "1s" PrivateKeys = [ - {Path = "/pk/aggregator.keystore", Password = "testonly"}, + {Path = "/etc/cdk/aggregator.keystore", Password = "pSnv6Dh5s9ahuzGzH9RoCDrKAMddaX3m"}, ] ForcedGas = 0 GasPriceMarginFactor = 1 @@ -88,34 +104,41 @@ SequencerPrivateKey = {} ReadPendingL1Txs = false SafeStatusL1NumberOfBlocks = 0 FinalizedStatusL1NumberOfBlocks = 0 - [Aggregator.EthTxManager.Etherman] - URL = "" - L1ChainID = 11155111 - HTTPHeaders = [] + [Aggregator.EthTxManager.Etherman] + URL = "http://el-1-geth-lighthouse:8545" + L1ChainID = 271828 + HTTPHeaders = [] [Aggregator.Synchronizer] [Aggregator.Synchronizer.DB] - Name = "sync_db" - User = "sync_user" - Password = "sync_password" - Host = "cdk-l1-sync-db" + Name = "aggregator_syncer_db" + User = "aggregator_syncer_db_user" + Password = "redacted" + Host = "postgres-001" Port = "5432" EnableLog = false MaxConns = 10 [Aggregator.Synchronizer.Synchronizer] SyncInterval = "10s" SyncChunkSize = 1000 - GenesisBlockNumber = 5511080 - SyncUpToBlock = "finalized" - BlockFinality = "finalized" + GenesisBlockNumber = 1 + SyncUpToBlock = "latest" + BlockFinality = "latest" OverrideStorageCheck = false [Aggregator.Synchronizer.Etherman] [Aggregator.Synchronizer.Etherman.Validium] - Enabled = false + Enabled = true -[RPC] +[L1InfoTreeSync] +DBPath = "/tmp/L1InfoTreeSync" # TODO: put a more realisitic path here +GlobalExitRootAddr = "0x1f7ad7caA53e35b4f0D138dC5CBF91aC108a2674" +SyncBlockChunkSize = 10 +BlockFinality = "LatestBlock" +URLRPCL1 = "http://el-1-geth-lighthouse:8545" +WaitForNewBlocksPeriod = "1s" +InitialBlock = 0 # TODO: should be block were rollup manager was deployed [NetworkConfig.L1] -ChainID = 11155111 +L1ChainID = 271828 PolAddr = "0xEdE9cf798E0fE25D35469493f43E88FeA4a5da0E" ZkEVMAddr = "0x1Fe038B54aeBf558638CA51C91bC8cCa06609e91" RollupManagerAddr = "0x2F50ef6b8e8Ee4E579B17619A92dE3E2ffbD8AD2" diff --git a/crates/cdk-config/src/aggregator.rs b/crates/cdk-config/src/aggregator.rs new file mode 100644 index 00000000..91df76ca --- /dev/null +++ b/crates/cdk-config/src/aggregator.rs @@ -0,0 +1,120 @@ +use ethers::types::Address; +use serde::Deserialize; +use url::Url; + +/// The StreamClient configuration. +#[derive(Deserialize, Debug, Clone)] +pub struct StreamClient { + #[serde(rename = "Server")] + pub server: String, +} + +#[derive(Deserialize, Debug, Clone)] +pub struct EthTxManager { + #[serde(rename = "Etherman")] + pub etherman: Etherman, +} + +#[derive(Deserialize, Debug, Clone)] +pub struct Etherman { + #[serde(rename = "URL")] + pub url: String, +} + +/// The Aggregator configuration. +#[derive(Deserialize, Debug, Clone)] +pub struct Aggregator { + #[serde(rename = "ChainID")] + pub chain_id: String, + #[serde(rename = "Host")] + pub host: String, + #[serde(rename = "Port")] + pub port: String, + #[serde(rename = "RetryTime")] + pub retry_time: String, + #[serde(rename = "VerifyProofInterval")] + pub verify_proof_interval: String, + #[serde(rename = "ProofStatePollingInterval")] + pub proof_state_polling_interval: String, + #[serde(rename = "TxProfitabilityCheckerType")] + pub tx_profitability_checker_type: String, + #[serde(rename = "TxProfitabilityMinReward")] + pub tx_profitability_min_reward: String, + #[serde(rename = "IntervalAfterWhichBatchConsolidateAnyway")] + pub interval_after_which_batch_consolidate_anyway: String, + #[serde(rename = "ForkId")] + pub fork_id: u64, + #[serde(rename = "CleanupLockedProofsInterval")] + pub cleanup_locked_proofs_interval: String, + #[serde(rename = "GeneratingProofCleanupThreshold")] + pub generating_proof_cleanup_threshold: String, + #[serde(rename = "GasOffset")] + pub gas_offset: u64, + #[serde(rename = "WitnessURL")] + pub witness_url: Url, + #[serde(rename = "SenderAddress")] + pub sender_address: Address, + // #[serde(rename = "SequencerPrivateKey")] + // pub sequencer_private_key: SequencerPrivateKey, + #[serde(rename = "SettlementBackend")] + pub settlement_backend: String, + #[serde(rename = "AggLayerTxTimeout")] + pub agg_layer_tx_timeout: String, + #[serde(rename = "AggLayerURL")] + pub agg_layer_url: Url, + #[serde(rename = "UseL1BatchData")] + pub use_l1_batch_data: bool, + #[serde(rename = "UseFullWitness")] + pub use_full_witness: bool, + #[serde(rename = "MaxWitnessRetrievalWorkers")] + pub max_witness_retrieval_workers: u32, + #[serde(rename = "SyncModeOnlyEnabled")] + pub sync_mode_only_enabled: bool, + + #[serde(rename = "StreamClient")] + pub stream_client: StreamClient, + + #[serde(rename = "EthTxManager")] + pub eth_tx_manager: EthTxManager, +} + +#[cfg(any(test, feature = "testutils"))] +impl Default for Aggregator { + fn default() -> Self { + // Values are coming from https://github.com/0xPolygon/agglayer/blob/main/config/default.go#L11 + Self { + chain_id: "1".to_string(), + host: "localhost".to_string(), + port: "8545".to_string(), + retry_time: "10s".to_string(), + verify_proof_interval: "1m".to_string(), + proof_state_polling_interval: "10s".to_string(), + tx_profitability_checker_type: "default".to_string(), + tx_profitability_min_reward: "0.1".to_string(), + interval_after_which_batch_consolidate_anyway: "5m".to_string(), + fork_id: 0, + cleanup_locked_proofs_interval: "1h".to_string(), + generating_proof_cleanup_threshold: "10m".to_string(), + gas_offset: 0, + witness_url: Url::parse("http://localhost:8546").unwrap(), + sender_address: "0x0000000000000000000000000000000000000000" + .parse() + .unwrap(), + settlement_backend: "default".to_string(), + agg_layer_tx_timeout: "30s".to_string(), + agg_layer_url: Url::parse("http://localhost:8547").unwrap(), + use_l1_batch_data: true, + use_full_witness: false, + max_witness_retrieval_workers: 4, + sync_mode_only_enabled: false, + stream_client: StreamClient { + server: "localhost:9092".to_string(), + }, + eth_tx_manager: EthTxManager { + etherman: Etherman { + url: "http://localhost:9093".to_string(), + }, + }, + } + } +} diff --git a/crates/cdk-config/src/l1.rs b/crates/cdk-config/src/l1.rs new file mode 100644 index 00000000..55fb2fb6 --- /dev/null +++ b/crates/cdk-config/src/l1.rs @@ -0,0 +1,39 @@ +use ethers::types::Address; +use serde::Deserialize; + +/// The L1 configuration. +#[derive(Deserialize, Debug, Clone)] +pub struct L1 { + #[serde(rename = "L1ChainID")] + pub l1_chain_id: String, + #[serde(rename = "PolAddr")] + pub pol_addr: Address, + #[serde(rename = "ZkEVMAddr")] + pub zk_evm_addr: Address, + #[serde(rename = "RollupManagerAddr")] + pub rollup_manager_addr: Address, + #[serde(rename = "GlobalExitRootManagerAddr")] + pub global_exit_root_manager_addr: Address, +} + +#[cfg(any(test, feature = "testutils"))] +impl Default for L1 { + fn default() -> Self { + // Values are coming from https://github.com/0xPolygon/agglayer/blob/main/config/default.go#L11 + Self { + l1_chain_id: "1337".to_string(), + pol_addr: "0x5b06837A43bdC3dD9F114558DAf4B26ed49842Ed" + .parse() + .unwrap(), + zk_evm_addr: "0x2F50ef6b8e8Ee4E579B17619A92dE3E2ffbD8AD2" + .parse() + .unwrap(), + rollup_manager_addr: "0x1Fe038B54aeBf558638CA51C91bC8cCa06609e91" + .parse() + .unwrap(), + global_exit_root_manager_addr: "0x1f7ad7caA53e35b4f0D138dC5CBF91aC108a2674" + .parse() + .unwrap(), + } + } +} diff --git a/crates/cdk-config/src/layer1.rs b/crates/cdk-config/src/layer1.rs deleted file mode 100644 index a5bd19d0..00000000 --- a/crates/cdk-config/src/layer1.rs +++ /dev/null @@ -1,28 +0,0 @@ -use ethers::types::Address; -use serde::Deserialize; -use url::Url; - -/// The L1 configuration. -#[derive(Deserialize, Debug, Clone)] -pub struct Layer1 { - #[serde(rename = "ChainID")] - pub chain_id: u64, - #[serde(rename = "NodeURL")] - pub node_url: Url, - #[serde(rename = "RollupManagerContract")] - pub rollup_manager_contract: Address, -} - -#[cfg(any(test, feature = "testutils"))] -impl Default for Layer1 { - fn default() -> Self { - // Values are coming from https://github.com/0xPolygon/agglayer/blob/main/config/default.go#L11 - Self { - chain_id: 1337, - node_url: "http://zkevm-mock-l1-network:8545".parse().unwrap(), - rollup_manager_contract: "0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e" - .parse() - .unwrap(), - } - } -} diff --git a/crates/cdk-config/src/lib.rs b/crates/cdk-config/src/lib.rs index 13298073..cb3ecb8f 100644 --- a/crates/cdk-config/src/lib.rs +++ b/crates/cdk-config/src/lib.rs @@ -6,23 +6,33 @@ use serde::Deserialize; pub(crate) const DEFAULT_IP: std::net::Ipv4Addr = std::net::Ipv4Addr::new(0, 0, 0, 0); -pub(crate) mod layer1; +pub(crate) mod aggregator; +pub(crate) mod l1; pub mod log; +pub(crate) mod network_config; +pub(crate) mod sequence_sender; pub(crate) mod telemetry; -pub use layer1::Layer1; pub use log::Log; +use sequence_sender::SequenceSender; /// The Agglayer configuration. #[derive(Deserialize, Debug)] #[cfg_attr(any(test, feature = "testutils"), derive(Default))] pub struct Config { - /// A map of Zkevm node RPC endpoints for each rollup. - /// /// The log configuration. #[serde(rename = "Log")] pub log: Log, #[serde(rename = "ForkUpgradeBatchNumber")] pub fork_upgrade_batch_number: Option, + + #[serde(rename = "NetworkConfig")] + pub network_config: network_config::NetworkConfig, + + #[serde(rename = "Aggregator")] + pub aggregator: aggregator::Aggregator, + + #[serde(rename = "SequenceSender")] + pub sequence_sender: SequenceSender, } diff --git a/crates/cdk-config/src/network_config.rs b/crates/cdk-config/src/network_config.rs new file mode 100644 index 00000000..ffabffad --- /dev/null +++ b/crates/cdk-config/src/network_config.rs @@ -0,0 +1,16 @@ +use crate::l1::L1; +use serde::Deserialize; + +/// The L1 configuration. +#[derive(Deserialize, Debug, Clone)] +pub struct NetworkConfig { + #[serde(rename = "L1")] + pub l1: L1, +} + +#[cfg(any(test, feature = "testutils"))] +impl Default for NetworkConfig { + fn default() -> Self { + Self { l1: L1::default() } + } +} diff --git a/crates/cdk-config/src/sequence_sender.rs b/crates/cdk-config/src/sequence_sender.rs new file mode 100644 index 00000000..006547e8 --- /dev/null +++ b/crates/cdk-config/src/sequence_sender.rs @@ -0,0 +1,50 @@ +use serde::Deserialize; + +/// The SequenceSender configuration. +#[derive(Deserialize, Debug, Clone)] +pub struct SequenceSender { + #[serde(rename = "WaitPeriodSendSequence")] + pub wait_period_send_sequence: String, + #[serde(rename = "LastBatchVirtualizationTimeMaxWaitPeriod")] + pub last_batch_virtualization_time_max_wait_period: String, + #[serde(rename = "MaxTxSizeForL1")] + pub max_tx_size_for_l1: u32, + #[serde(rename = "L2Coinbase")] + pub l2_coinbase: String, + #[serde(rename = "SequencesTxFileName")] + pub sequences_tx_file_name: String, + #[serde(rename = "GasOffset")] + pub gas_offset: u64, + #[serde(rename = "WaitPeriodPurgeTxFile")] + pub wait_period_purge_tx_file: String, + #[serde(rename = "MaxPendingTx")] + pub max_pending_tx: u32, + #[serde(rename = "MaxBatchesForL1")] + pub max_batches_for_l1: u32, + #[serde(rename = "BlockFinality")] + pub block_finality: String, + #[serde(rename = "RPCURL")] + pub rpc_url: String, + #[serde(rename = "GetBatchWaitInterval")] + pub get_batch_wait_interval: String, +} + +// Default trait implementation +impl Default for SequenceSender { + fn default() -> Self { + Self { + wait_period_send_sequence: "1s".to_string(), + last_batch_virtualization_time_max_wait_period: "1s".to_string(), + max_tx_size_for_l1: 1000, + l2_coinbase: "0x".to_string(), + sequences_tx_file_name: "sequences_tx.json".to_string(), + gas_offset: 0, + wait_period_purge_tx_file: "1s".to_string(), + max_pending_tx: 1000, + max_batches_for_l1: 100, + block_finality: "1s".to_string(), + rpc_url: "http://localhost:8545".to_string(), + get_batch_wait_interval: "1s".to_string(), + } + } +} diff --git a/crates/cdk/Cargo.toml b/crates/cdk/Cargo.toml index 913fc492..d03853ea 100644 --- a/crates/cdk/Cargo.toml +++ b/crates/cdk/Cargo.toml @@ -16,3 +16,6 @@ tracing-subscriber = { workspace = true, features = ["env-filter", "json"] } cdk-config = { path = "../cdk-config" } +serde.workspace = true +serde_json.workspace = true +tempfile = "3.12.0" diff --git a/crates/cdk/src/allocs_render.rs b/crates/cdk/src/allocs_render.rs new file mode 100644 index 00000000..ae7bc514 --- /dev/null +++ b/crates/cdk/src/allocs_render.rs @@ -0,0 +1,97 @@ +use anyhow::{Context, Result}; +use serde::{Deserialize, Serialize}; +use serde_json::{self, Value}; +use std::collections::HashMap; +use std::fs::File; +use std::io::Read; +use std::path::Path; + +#[derive(Serialize, Deserialize, Debug, Clone)] +struct Input { + #[serde(rename = "contractName", skip_serializing_if = "Option::is_none")] + contract_name: Option, + #[serde(rename = "accountName", skip_serializing_if = "Option::is_none")] + account_name: Option, + balance: String, + nonce: String, + address: String, + #[serde(skip_serializing_if = "Option::is_none")] + bytecode: Option, + #[serde(skip_serializing_if = "Option::is_none")] + storage: Option>, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct Wrapper { + pub root: String, + #[serde(rename = "L1Config")] + pub l1_config: L1Config, + genesis: Vec, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct L1Config { + #[serde(rename = "chainId")] + pub chain_id: u64, + #[serde(rename = "polygonZkEVMGlobalExitRootAddress")] + pub zkevm_global_exit_root_address: String, + #[serde(rename = "polygonRollupManagerAddress")] + pub rollup_manager_address: String, + #[serde(rename = "polTokenAddress")] + pub pol_token_address: String, + #[serde(rename = "polygonZkEVMAddress")] + pub zkevm_address: String, +} + +#[derive(Serialize, Deserialize, Debug)] +struct Output { + #[serde(rename = "contractName", skip_serializing_if = "Option::is_none")] + contract_name: Option, + #[serde(rename = "accountName", skip_serializing_if = "Option::is_none")] + account_name: Option, + balance: Option, + nonce: Option, + code: Option, + storage: Option, +} + +pub struct Rendered { + pub output: String, + pub wrapper: Wrapper, +} + +pub fn render_allocs(genesis_file_path: &str) -> Result { + let path = Path::new(genesis_file_path); + let display = path.display(); + + let mut file = File::open(&path).with_context(|| format!("couldn't open {}", display))?; + + let mut data = String::new(); + file.read_to_string(&mut data) + .with_context(|| format!("couldn't read {}", display))?; + + let wrapper: Wrapper = serde_json::from_str(&data) + .with_context(|| format!("couldn't parse JSON from {}", display))?; + + let mut outputs: HashMap = HashMap::new(); + + for input in wrapper.genesis.clone() { + let output = Output { + contract_name: input.contract_name, + account_name: input.account_name, + balance: Some(input.balance), + nonce: Some(input.nonce), + code: input.bytecode, + storage: input.storage.map(|s| serde_json::to_value(s).unwrap()), + }; + outputs.insert(input.address, output); + } + + // outputs.sort_by(|a, b| a.contract_name.cmp(&b.contract_name)); + + Ok(Rendered { + output: serde_json::to_string_pretty(&outputs) + .with_context(|| "couldn't serialize outputs to JSON")?, + wrapper, + }) +} diff --git a/crates/cdk/src/cli.rs b/crates/cdk/src/cli.rs index 1bf29d2c..31c3ba12 100644 --- a/crates/cdk/src/cli.rs +++ b/crates/cdk/src/cli.rs @@ -11,8 +11,6 @@ pub(crate) struct Cli { long, short, value_hint = ValueHint::FilePath, - global = true, - default_value = "config/example-config.toml", env = "CDK_CONFIG_PATH" )] pub(crate) config: PathBuf, @@ -22,8 +20,6 @@ pub(crate) struct Cli { long, short = 'g', value_hint = ValueHint::FilePath, - global = true, - default_value = "config/genesis.json", env = "CDK_GENESIS_PATH" )] pub(crate) chain: PathBuf, diff --git a/crates/cdk/src/config_render.rs b/crates/cdk/src/config_render.rs new file mode 100644 index 00000000..a213bd67 --- /dev/null +++ b/crates/cdk/src/config_render.rs @@ -0,0 +1,157 @@ +use anyhow::Error; +use std::fs; +use std::path::PathBuf; +use tempfile::{tempdir, TempDir}; + +pub fn render( + chain_id: String, + l2_sequencer_rpc_url: String, + datastreamer_host: String, + l1_rpc_url: String, + sequencer_address: String, + genesis_file: PathBuf, +) -> Result { + // Create a temporary directory + let tmp_dir = tempdir()?; + + let res = crate::allocs_render::render_allocs(genesis_file.to_str().unwrap())?; + // Write the three files to disk + fs::write( + tmp_dir + .path() + .join(format!("dynamic-{}-allocs.json", chain_id.clone())), + res.output, + )?; + fs::write( + tmp_dir + .path() + .join(format!("dynamic-{}-chainspec.json", chain_id.clone())), + render_chainspec(chain_id.clone()), + )?; + fs::write( + tmp_dir + .path() + .join(format!("dynamic-{}-conf.json", chain_id.clone())), + render_conf(res.wrapper.root, 1000000000000000000), + )?; + + let zkevm_address = res.wrapper.l1_config.zkevm_address; + // admin_address: String, + let rollup_address = res.wrapper.l1_config.rollup_manager_address; + let ger_manager_address = res.wrapper.l1_config.zkevm_global_exit_root_address; + let matic_contract_address = res.wrapper.l1_config.pol_token_address; + + fs::write( + tmp_dir + .path() + .join(format!("dynamic-{}.yaml", chain_id.clone())), + render_yaml( + chain_id, + l2_sequencer_rpc_url, + datastreamer_host, + l1_rpc_url, + sequencer_address, + zkevm_address, + "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef".to_string(), + rollup_address, + ger_manager_address, + matic_contract_address, + ), + )?; + + Ok(tmp_dir) +} + +fn render_chainspec(chain_id: String) -> String { + format!( + r#" +{{ + "ChainName": "dynamic-{chain_id}", + "chainId": {chain_id}, + "consensus": "ethash", + "homesteadBlock": 0, + "daoForkBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 9999999999999999999999999999999999999999999999999, + "arrowGlacierBlock": 9999999999999999999999999999999999999999999999999, + "grayGlacierBlock": 9999999999999999999999999999999999999999999999999, + "terminalTotalDifficulty": 58750000000000000000000, + "terminalTotalDifficultyPassed": false, + "shanghaiTime": 9999999999999999999999999999999999999999999999999, + "cancunTime": 9999999999999999999999999999999999999999999999999, + "pragueTime": 9999999999999999999999999999999999999999999999999, + "ethash": {{}} +}} + "# + ) +} + +fn render_conf(root: String, gas_limit: u64) -> String { + format!( + r#" +{{ + "root": {:?}, + "timestamp": 0, + "gasLimit": {:?}, + "difficulty": 0 +}} + "#, + root, gas_limit + ) +} + +// render_config renders the configuration file for the Erigon node. +fn render_yaml( + chain_id: String, + l2_sequencer_rpc_url: String, + datastreamer_host: String, + l1_rpc_url: String, + sequencer_address: String, + zkevm_address: String, + admin_address: String, + rollup_address: String, + ger_manager_address: String, + matic_contract_address: String, +) -> String { + format!( + r#" +datadir: ./data/dynamic-{chain_id} +chain: dynamic-{chain_id} +http: true +private.api.addr: localhost:9092 +zkevm.l2-chain-id: {chain_id} +zkevm.l2-sequencer-rpc-url: {l2_sequencer_rpc_url} +zkevm.l2-datastreamer-url: {datastreamer_host} +zkevm.l1-chain-id: 271828 +zkevm.l1-rpc-url: {l1_rpc_url} + +zkevm.address-sequencer: {sequencer_address} +zkevm.address-zkevm: {zkevm_address} +zkevm.address-admin: {admin_address} +zkevm.address-rollup: {rollup_address} +zkevm.address-ger-manager: {ger_manager_address} + +zkevm.l1-rollup-id: 1 +zkevm.l1-matic-contract-address: {matic_contract_address} +zkevm.l1-first-block: 23 +zkevm.rpc-ratelimit: 250 +txpool.disable: true +torrent.port: 42070 +zkevm.datastream-version: 2 + +externalcl: true +http.api: [eth, debug, net, trace, web3, erigon, zkevm] +http.addr: 0.0.0.0 +http.vhosts: any +http.corsdomain: any +ws: true +"# + ) +} diff --git a/crates/cdk/src/main.rs b/crates/cdk/src/main.rs index 99a8a752..df9d3751 100644 --- a/crates/cdk/src/main.rs +++ b/crates/cdk/src/main.rs @@ -6,28 +6,58 @@ use execute::Execute; use std::env; use std::path::PathBuf; use std::process::Command; -use std::sync::Arc; +use tracing::debug; +pub mod allocs_render; mod cli; +mod config_render; mod logging; -const CDK_CLIENT_PATH: &str = "cdk-node"; -const CDK_ERIGON_PATH: &str = "cdk-erigon"; +const CDK_CLIENT_BIN: &str = "cdk-node"; +const CDK_ERIGON_BIN: &str = "cdk-erigon"; fn main() -> anyhow::Result<()> { dotenvy::dotenv().ok(); let cli = Cli::parse(); + // Read the config + let config = read_config(cli.config.clone())?; + + // Initialize the logger + logging::tracing(&config.log); + + println!( + r#"🐼 + _____ _ _____ _____ _ __ + | __ \ | | / ____| __ \| |/ / + | |__) |__ | |_ _ __ _ ___ _ __ | | | | | | ' / + | ___/ _ \| | | | |/ _` |/ _ \| '_ \ | | | | | | < + | | | (_) | | |_| | (_| | (_) | | | | | |____| |__| | . \ + |_| \___/|_|\__, |\__, |\___/|_| |_| \_____|_____/|_|\_\ + __/ | __/ | + |___/ |___/ +"# + ); + match cli.cmd { cli::Commands::Node {} => node(cli.config)?, - cli::Commands::Erigon {} => erigon(cli.config)?, + cli::Commands::Erigon {} => erigon(config, cli.chain)?, // _ => forward()?, } Ok(()) } +// read_config reads the configuration file and returns the configuration. +fn read_config(config_path: PathBuf) -> anyhow::Result { + let config = std::fs::read_to_string(config_path) + .map_err(|e| anyhow::anyhow!("Failed to read configuration file: {}", e))?; + let config: Config = toml::from_str(&config)?; + + Ok(config) +} + /// This is the main node entrypoint. /// /// This function starts everything needed to run an Agglayer node. @@ -37,23 +67,11 @@ fn main() -> anyhow::Result<()> { /// This function returns on fatal error or after graceful shutdown has /// completed. pub fn node(config_path: PathBuf) -> anyhow::Result<()> { - // Load the configuration file - let config_read = std::fs::read_to_string(config_path.clone()); - let toml_str = match config_read { - Ok(toml) => toml, - Err(e) => { - eprintln!( - "Failed to read configuration file, from path: {}", - config_path.to_str().unwrap() - ); - return Err(e.into()); - } - }; - let config: Arc = Arc::new(toml::from_str(&toml_str)?); - - let mut bin_path = env::var("CARGO_MANIFEST_DIR").unwrap_or(CDK_CLIENT_PATH.into()); - if bin_path != CDK_CLIENT_PATH { - bin_path = format!("{}/../../{}", bin_path, CDK_CLIENT_PATH); + // This is to find the erigon binary when running in development mode + // otherwise it will use system path + let mut bin_path = env::var("CARGO_MANIFEST_DIR").unwrap_or(CDK_CLIENT_BIN.into()); + if bin_path != CDK_CLIENT_BIN { + bin_path = format!("{}/../../{}", bin_path, CDK_CLIENT_BIN); } // Run the node passing the config file path as argument @@ -82,38 +100,44 @@ pub fn node(config_path: PathBuf) -> anyhow::Result<()> { eprintln!("Interrupted!"); } - // Initialize the logger - logging::tracing(&config.log); - Ok(()) } /// This is the main erigon entrypoint. /// This function starts everything needed to run an Erigon node. -pub fn erigon(config_path: PathBuf) -> anyhow::Result<()> { - // Load the configuration file - let _config: Arc = Arc::new(toml::from_str(&std::fs::read_to_string( - config_path.clone(), - )?)?); - - let mut bin_path = env::var("CARGO_MANIFEST_DIR").unwrap_or(CDK_ERIGON_PATH.into()); - if bin_path != CDK_ERIGON_PATH { - bin_path = format!("{}/../../{}", bin_path, CDK_ERIGON_PATH); - } - - let mut command = Command::new(bin_path); - - // TODO: 1. Prepare erigon config files or flags - - command.args(&["--config", config_path.to_str().unwrap()]); - - let output = command.execute_output().unwrap(); +pub fn erigon(config: Config, genesis_file: PathBuf) -> anyhow::Result<()> { + // Render configuration files + let erigon_config_path = config_render::render( + config.aggregator.chain_id.clone(), + config.aggregator.witness_url.to_string(), + config.aggregator.stream_client.server, + config.aggregator.eth_tx_manager.etherman.url, + config.sequence_sender.l2_coinbase, + genesis_file, + )?; + + debug!("Starting erigon with config: {:?}", erigon_config_path); + + // Run cdk-erigon in system path + let output = Command::new(CDK_ERIGON_BIN) + .args(&[ + "--config", + erigon_config_path + .path() + .join(format!("dynamic-{}.yaml", config.aggregator.chain_id)) + .to_str() + .unwrap(), + ]) + .execute_output() + .unwrap(); if let Some(exit_code) = output.status.code() { - if exit_code == 0 { - println!("Ok."); - } else { - eprintln!("Failed."); + if exit_code != 0 { + eprintln!( + "Failed. Leaving configuration files in: {:?}", + erigon_config_path + ); + std::process::exit(1); } } else { eprintln!("Interrupted!");