From 669d14f9b5ada394d045c63f4067fbeaecfe9aea Mon Sep 17 00:00:00 2001 From: jfldde <168934971+jfldde@users.noreply.github.com> Date: Mon, 7 Oct 2024 22:35:36 +0100 Subject: [PATCH] Re-implement citrea configs and remove related dependencies --- Cargo.toml | 7 +- src/bitcoin.rs | 3 +- src/citrea_config/bitcoin.rs | 19 +++++ src/citrea_config/mod.rs | 29 ++++++++ src/citrea_config/prover.rs | 102 ++++++++++++++++++++++++++ src/citrea_config/rollup.rs | 120 ++++++++++++++++++++++++++++++ src/citrea_config/sequencer.rs | 130 +++++++++++++++++++++++++++++++++ src/config/mod.rs | 11 +-- src/lib.rs | 1 + 9 files changed, 412 insertions(+), 10 deletions(-) create mode 100644 src/citrea_config/bitcoin.rs create mode 100644 src/citrea_config/mod.rs create mode 100644 src/citrea_config/prover.rs create mode 100644 src/citrea_config/rollup.rs create mode 100644 src/citrea_config/sequencer.rs diff --git a/Cargo.toml b/Cargo.toml index e176710..19dd3b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,13 +20,12 @@ tokio = { version = "1.39", features = ["full"] } toml = "0.8.0" which = "6.0.1" jsonrpsee = { version = "0.24.2", features = ["http-client", "ws-client"] } +hex = { version = "0.4.3", default-features = false, features = ["serde"] } # Citrea dependencies -bitcoin-da = { git = "https://github.com/chainwayxyz/citrea", rev = "82bf52d", features = ["native"] } -citrea-sequencer = { git = "https://github.com/chainwayxyz/citrea", rev = "82bf52d" } -sov-ledger-rpc = { git = "https://github.com/chainwayxyz/citrea", rev = "82bf52d", features = ["client"] } +sov-ledger-rpc = { git = "https://github.com/chainwayxyz/citrea", rev = "82bf52d", default-features = false, features = ["client"] } sov-rollup-interface = { git = "https://github.com/chainwayxyz/citrea", rev = "82bf52d" } -sov-stf-runner = { git = "https://github.com/chainwayxyz/citrea", rev = "82bf52d", features = ["native"] } +syn = { version = "1.0", features = ["full", "extra-traits"] } [patch.crates-io] bitcoincore-rpc = { version = "0.18.0", git = "https://github.com/chainwayxyz/rust-bitcoincore-rpc.git", rev = "0ae498d" } diff --git a/src/bitcoin.rs b/src/bitcoin.rs index 19c83bd..25dfc90 100644 --- a/src/bitcoin.rs +++ b/src/bitcoin.rs @@ -8,7 +8,6 @@ use std::{ use anyhow::{bail, Context}; use async_trait::async_trait; use bitcoin::Address; -use bitcoin_da::service::FINALITY_DEPTH; use bitcoincore_rpc::{json::AddressType::Bech32m, Auth, Client, RpcApi}; use futures::TryStreamExt; use tokio::{process::Command, sync::OnceCell, time::sleep}; @@ -22,6 +21,8 @@ use super::{ }; use crate::node::NodeKind; +pub const FINALITY_DEPTH: u64 = 8; + pub struct BitcoinNode { spawn_output: SpawnOutput, pub config: BitcoinConfig, diff --git a/src/citrea_config/bitcoin.rs b/src/citrea_config/bitcoin.rs new file mode 100644 index 0000000..e4119ff --- /dev/null +++ b/src/citrea_config/bitcoin.rs @@ -0,0 +1,19 @@ +use serde::{Deserialize, Serialize}; + +/// Runtime configuration for the DA service +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +pub struct BitcoinServiceConfig { + /// The URL of the Bitcoin node to connect to + pub node_url: String, + pub node_username: String, + pub node_password: String, + + // network of the bitcoin node + pub network: bitcoin::Network, + + // da private key of the sequencer + pub da_private_key: Option, + + // absolute path to the directory where the txs will be written to + pub tx_backup_dir: String, +} diff --git a/src/citrea_config/mod.rs b/src/citrea_config/mod.rs new file mode 100644 index 0000000..27e0d70 --- /dev/null +++ b/src/citrea_config/mod.rs @@ -0,0 +1,29 @@ +// Config imported as is from `citrea` repository `node-config` directory. +// This is done in order not to have cyclical dependencies with `citrea`. +// Should ideally be automatically kept in sync somehow but manually copied here for the time being. +// Configs are stable and not expected to change much. + +pub(crate) mod bitcoin; +pub(crate) mod prover; +pub(crate) mod rollup; +pub(crate) mod sequencer; + +#[cfg(test)] +/// Reads toml file as a specific type. +pub fn from_toml_path, R: serde::de::DeserializeOwned>( + path: P, +) -> anyhow::Result { + use std::{fs::File, io::Read}; + + let mut contents = String::new(); + { + let mut file = File::open(path)?; + file.read_to_string(&mut contents)?; + } + log::debug!("Config file size: {} bytes", contents.len()); + log::trace!("Config file contents: {}", &contents); + + let result: R = toml::from_str(&contents)?; + + Ok(result) +} diff --git a/src/citrea_config/prover.rs b/src/citrea_config/prover.rs new file mode 100644 index 0000000..367674d --- /dev/null +++ b/src/citrea_config/prover.rs @@ -0,0 +1,102 @@ +use serde::{Deserialize, Serialize}; + +/// The possible configurations of the prover. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)] +#[serde(rename_all = "lowercase")] +pub enum ProverGuestRunConfig { + /// Skip proving. + Skip, + /// Run the rollup verification logic inside the current process. + Simulate, + /// Run the rollup verifier in a zkVM executor. + Execute, + /// Run the rollup verifier and create a SNARK of execution. + Prove, +} + +impl<'de> Deserialize<'de> for ProverGuestRunConfig { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + match s.as_str() { + "skip" => Ok(ProverGuestRunConfig::Skip), + "simulate" => Ok(ProverGuestRunConfig::Simulate), + "execute" => Ok(ProverGuestRunConfig::Execute), + "prove" => Ok(ProverGuestRunConfig::Prove), + _ => Err(serde::de::Error::custom("invalid prover guest run config")), + } + } +} + +/// Prover configuration +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +pub struct ProverConfig { + /// Prover run mode + pub proving_mode: ProverGuestRunConfig, + /// Average number of commitments to prove + pub proof_sampling_number: usize, + /// If true prover will try to recover ongoing proving sessions + pub enable_recovery: bool, +} + +impl Default for ProverConfig { + fn default() -> Self { + Self { + proving_mode: ProverGuestRunConfig::Execute, + proof_sampling_number: 0, + enable_recovery: true, + } + } +} + +#[cfg(test)] +mod tests { + use std::io::Write; + + use serde::de::DeserializeOwned; + use std::fs::File; + use std::io::Read; + use std::path::Path; + use tempfile::NamedTempFile; + + use super::*; + + /// Reads toml file as a specific type. + pub fn from_toml_path, R: DeserializeOwned>(path: P) -> anyhow::Result { + let mut contents = String::new(); + { + let mut file = File::open(path)?; + file.read_to_string(&mut contents)?; + } + let result: R = toml::from_str(&contents)?; + + Ok(result) + } + + fn create_config_from(content: &str) -> NamedTempFile { + let mut config_file = NamedTempFile::new().unwrap(); + config_file.write_all(content.as_bytes()).unwrap(); + config_file + } + + #[test] + fn test_correct_prover_config() { + let config = r#" + proving_mode = "skip" + proof_sampling_number = 500 + enable_recovery = true + "#; + + let config_file = create_config_from(config); + + let config: ProverConfig = from_toml_path(config_file.path()).unwrap(); + let expected = ProverConfig { + proving_mode: ProverGuestRunConfig::Skip, + proof_sampling_number: 500, + enable_recovery: true, + }; + assert_eq!(config, expected); + } +} diff --git a/src/citrea_config/rollup.rs b/src/citrea_config/rollup.rs new file mode 100644 index 0000000..1e39c6d --- /dev/null +++ b/src/citrea_config/rollup.rs @@ -0,0 +1,120 @@ +use std::path::PathBuf; + +use serde::{Deserialize, Serialize}; + +/// Runner configuration. +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +pub struct RunnerConfig { + /// Sequencer client configuration. + pub sequencer_client_url: String, + /// Saves sequencer soft confirmations if set to true + pub include_tx_body: bool, + /// Only true for tests + pub accept_public_input_as_proven: Option, + /// Number of blocks to request during sync + #[serde(default = "default_sync_blocks_count")] + pub sync_blocks_count: u64, +} + +/// RPC configuration. +#[derive(Debug, Clone, PartialEq, Deserialize, Default, Serialize)] +pub struct RpcConfig { + /// RPC host. + pub bind_host: String, + /// RPC port. + pub bind_port: u16, + /// Maximum number of concurrent requests. + /// if not set defaults to 100. + #[serde(default = "default_max_connections")] + pub max_connections: u32, + /// Max request body request + #[serde(default = "default_max_request_body_size")] + pub max_request_body_size: u32, + /// Max response body request + #[serde(default = "default_max_response_body_size")] + pub max_response_body_size: u32, + /// Maximum number of batch requests + #[serde(default = "default_batch_requests_limit")] + pub batch_requests_limit: u32, + /// Disable subscription RPCs + #[serde(default = "default_enable_subscriptions")] + pub enable_subscriptions: bool, + /// Maximum number of subscription connections + #[serde(default = "default_max_subscriptions_per_connection")] + pub max_subscriptions_per_connection: u32, +} + +#[inline] +const fn default_max_connections() -> u32 { + 100 +} + +#[inline] +const fn default_max_request_body_size() -> u32 { + 10 * 1024 * 1024 +} + +#[inline] +const fn default_max_response_body_size() -> u32 { + 10 * 1024 * 1024 +} + +#[inline] +const fn default_batch_requests_limit() -> u32 { + 50 +} + +#[inline] +const fn default_sync_blocks_count() -> u64 { + 10 +} + +#[inline] +const fn default_enable_subscriptions() -> bool { + true +} + +#[inline] +const fn default_max_subscriptions_per_connection() -> u32 { + 100 +} + +/// Simple storage configuration +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +pub struct StorageConfig { + /// Path that can be utilized by concrete rollup implementation + pub path: PathBuf, + /// File descriptor limit for RocksDB + pub db_max_open_files: Option, +} + +/// Important public keys for the rollup +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +pub struct RollupPublicKeys { + /// Soft confirmation signing public key of the Sequencer + #[serde(with = "hex::serde")] + pub sequencer_public_key: Vec, + /// DA Signing Public Key of the Sequencer + /// serialized as hex + #[serde(with = "hex::serde")] + pub sequencer_da_pub_key: Vec, + /// DA Signing Public Key of the Prover + /// serialized as hex + #[serde(with = "hex::serde")] + pub prover_da_pub_key: Vec, +} + +/// Rollup Configuration +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +pub struct FullNodeConfig { + /// RPC configuration + pub rpc: RpcConfig, + /// Currently rollup config runner only supports storage path parameter + pub storage: StorageConfig, + /// Runner own configuration. + pub runner: Option, // optional bc sequencer doesn't need it + /// Data Availability service configuration. + pub da: BitcoinServiceConfig, + /// Important pubkeys + pub public_keys: RollupPublicKeys, +} diff --git a/src/citrea_config/sequencer.rs b/src/citrea_config/sequencer.rs new file mode 100644 index 0000000..4c8dfa8 --- /dev/null +++ b/src/citrea_config/sequencer.rs @@ -0,0 +1,130 @@ +use serde::{Deserialize, Serialize}; + +/// Rollup Configuration +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +pub struct SequencerConfig { + /// Private key of the sequencer + pub private_key: String, + /// Min. soft confirmaitons for sequencer to commit + pub min_soft_confirmations_per_commitment: u64, + /// Whether or not the sequencer is running in test mode + pub test_mode: bool, + /// Limit for the number of deposit transactions to be included in the block + pub deposit_mempool_fetch_limit: usize, + /// Sequencer specific mempool config + pub mempool_conf: SequencerMempoolConfig, + /// DA layer update loop interval in ms + pub da_update_interval_ms: u64, + /// Block production interval in ms + pub block_production_interval_ms: u64, +} + +impl Default for SequencerConfig { + fn default() -> Self { + SequencerConfig { + private_key: "1212121212121212121212121212121212121212121212121212121212121212" + .to_string(), + min_soft_confirmations_per_commitment: 4, + test_mode: true, + deposit_mempool_fetch_limit: 10, + block_production_interval_ms: 100, + da_update_interval_ms: 100, + mempool_conf: Default::default(), + } + } +} + +/// Mempool Config for the sequencer +/// Read: https://github.com/ledgerwatch/erigon/wiki/Transaction-Pool-Design +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +pub struct SequencerMempoolConfig { + /// Max number of transactions in the pending sub-pool + pub pending_tx_limit: u64, + /// Max megabytes of transactions in the pending sub-pool + pub pending_tx_size: u64, + /// Max number of transactions in the queued sub-pool + pub queue_tx_limit: u64, + /// Max megabytes of transactions in the queued sub-pool + pub queue_tx_size: u64, + /// Max number of transactions in the base-fee sub-pool + pub base_fee_tx_limit: u64, + /// Max megabytes of transactions in the base-fee sub-pool + pub base_fee_tx_size: u64, + /// Max number of executable transaction slots guaranteed per account + pub max_account_slots: u64, +} + +impl Default for SequencerMempoolConfig { + fn default() -> Self { + Self { + pending_tx_limit: 100000, + pending_tx_size: 200, + queue_tx_limit: 100000, + queue_tx_size: 200, + base_fee_tx_limit: 100000, + base_fee_tx_size: 200, + max_account_slots: 16, + } + } +} + +#[cfg(test)] +mod tests { + use std::io::Write; + + use tempfile::NamedTempFile; + + use crate::citrea_config::from_toml_path; + + use super::*; + + fn create_config_from(content: &str) -> NamedTempFile { + let mut config_file = NamedTempFile::new().unwrap(); + config_file.write_all(content.as_bytes()).unwrap(); + config_file + } + + #[test] + fn test_correct_config_sequencer() { + let config = r#" + private_key = "1212121212121212121212121212121212121212121212121212121212121212" + min_soft_confirmations_per_commitment = 123 + test_mode = false + deposit_mempool_fetch_limit = 10 + da_update_interval_ms = 1000 + block_production_interval_ms = 1000 + [mempool_conf] + pending_tx_limit = 100000 + pending_tx_size = 200 + queue_tx_limit = 100000 + queue_tx_size = 200 + base_fee_tx_limit = 100000 + base_fee_tx_size = 200 + max_account_slots = 16 + "#; + + let config_file = create_config_from(config); + + let config: SequencerConfig = from_toml_path(config_file.path()).unwrap(); + + let expected = SequencerConfig { + private_key: "1212121212121212121212121212121212121212121212121212121212121212" + .to_string(), + min_soft_confirmations_per_commitment: 123, + test_mode: false, + deposit_mempool_fetch_limit: 10, + mempool_conf: SequencerMempoolConfig { + pending_tx_limit: 100000, + pending_tx_size: 200, + queue_tx_limit: 100000, + queue_tx_size: 200, + base_fee_tx_limit: 100000, + base_fee_tx_size: 200, + max_account_slots: 16, + }, + da_update_interval_ms: 1000, + block_production_interval_ms: 1000, + }; + assert_eq!(config, expected); + } +} diff --git a/src/config/mod.rs b/src/config/mod.rs index 443933d..d036ef8 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -7,15 +7,16 @@ mod utils; use std::path::PathBuf; +pub use crate::citrea_config::bitcoin::BitcoinServiceConfig; +pub use crate::citrea_config::prover::ProverConfig; +pub use crate::citrea_config::rollup::{ + FullNodeConfig, RollupPublicKeys, RpcConfig, RunnerConfig, StorageConfig, +}; +pub use crate::citrea_config::sequencer::SequencerConfig; pub use bitcoin::BitcoinConfig; -pub use bitcoin_da::service::BitcoinServiceConfig; -pub use citrea_sequencer::SequencerConfig; pub use docker::DockerConfig; pub use rollup::{default_rollup_config, RollupConfig}; use serde::Serialize; -pub use sov_stf_runner::{ - FullNodeConfig, ProverConfig, RollupPublicKeys, RpcConfig, RunnerConfig, StorageConfig, -}; pub use test::TestConfig; pub use test_case::{TestCaseConfig, TestCaseEnv}; pub use utils::config_to_file; diff --git a/src/lib.rs b/src/lib.rs index 3bb6283..119cf52 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ pub mod bitcoin; +mod citrea_config; mod client; pub mod config; mod docker;