diff --git a/crates/rollup-boost/src/tests/common/mod.rs b/crates/rollup-boost/src/tests/common/mod.rs index 7d6f2a13..9e397acf 100644 --- a/crates/rollup-boost/src/tests/common/mod.rs +++ b/crates/rollup-boost/src/tests/common/mod.rs @@ -1,5 +1,8 @@ #![allow(dead_code)] use crate::DebugClient; +use crate::tests::common::services::op_rbuilder::{ + FLASHBLOCKS_PORT, OpRbuilderConfig, OpRbuilderImage, OpRbuilderMehods, +}; use crate::{AuthLayer, AuthService}; use crate::{EngineApiClient, OpExecutionPayloadEnvelope, PayloadVersion}; use crate::{NewPayload, PayloadSource}; @@ -15,6 +18,7 @@ use bytes::BytesMut; use eyre::{Context, ContextCompat}; use futures::FutureExt; use futures::future::BoxFuture; +use http::Uri; use jsonrpsee::core::middleware::layer::RpcLogger; use jsonrpsee::http_client::RpcService; use jsonrpsee::http_client::{HttpClient, transport::HttpBackend}; @@ -218,10 +222,38 @@ impl Genesis { } } +pub enum Builder { + Flashblocks(ContainerAsync), + Reth(ContainerAsync), +} + +impl Builder { + pub fn id(&self) -> &str { + match self { + Builder::Flashblocks(builder) => builder.id(), + Builder::Reth(builder) => builder.id(), + } + } + + pub async fn auth_rpc_port(&self) -> eyre::Result { + match self { + Builder::Flashblocks(builder) => builder.auth_rpc_port().await, + Builder::Reth(builder) => builder.auth_rpc_port().await, + } + } + + pub async fn auth_rpc(&self) -> eyre::Result { + match self { + Builder::Flashblocks(builder) => builder.auth_rpc().await, + Builder::Reth(builder) => builder.auth_rpc().await, + } + } +} + /// Test flavor that sets up one Rollup-boost instance connected to two Reth nodes pub struct RollupBoostTestHarness { pub l2: ContainerAsync, - pub builder: ContainerAsync, + pub builder: Builder, pub rollup_boost: RollupBoost, pub genesis: Genesis, } @@ -231,6 +263,7 @@ pub struct RollupBoostTestHarnessBuilder { proxy_handler: Option>, isthmus_block: Option, block_time: u64, + flashblocks: bool, } impl RollupBoostTestHarnessBuilder { @@ -240,9 +273,15 @@ impl RollupBoostTestHarnessBuilder { proxy_handler: None, isthmus_block: None, block_time: 1, + flashblocks: false, } } + pub fn with_flashblocks(mut self, flashblocks: bool) -> Self { + self.flashblocks = flashblocks; + self + } + pub fn with_isthmus_block(mut self, isthmus_block: u64) -> Self { self.isthmus_block = Some(isthmus_block); self @@ -332,17 +371,37 @@ impl RollupBoostTestHarnessBuilder { let l2_enode = format!("enode://{}@{}:{}", L2_P2P_ENODE, name, P2P_PORT); let builder_p2p_port = get_available_port(); - let builder = OpRethConfig::default() - .set_trusted_peers(vec![l2_enode]) - .set_genesis(genesis_str) - .build()? - .with_mapped_port(builder_p2p_port, ContainerPort::Tcp(P2P_PORT)) - .with_mapped_port(builder_p2p_port, ContainerPort::Udp(P2P_PORT)) - .with_mapped_port(get_available_port(), ContainerPort::Tcp(AUTH_RPC_PORT)) - .with_network(&network) - .with_log_consumer(builder_log_consumer) - .start() - .await?; + let builder = if self.flashblocks { + let builder = OpRbuilderConfig::default() + .set_trusted_peers(vec![l2_enode]) + .set_genesis(genesis_str) + .set_flashblocks(self.flashblocks) + .build()? + .with_mapped_port(builder_p2p_port, ContainerPort::Tcp(P2P_PORT)) + .with_mapped_port(builder_p2p_port, ContainerPort::Udp(P2P_PORT)) + .with_mapped_port(get_available_port(), ContainerPort::Tcp(AUTH_RPC_PORT)) + .with_mapped_port(get_available_port(), ContainerPort::Tcp(FLASHBLOCKS_PORT)) + .with_network(&network) + .with_log_consumer(builder_log_consumer) + .start() + .await?; + + Builder::Flashblocks(builder) + } else { + let builder = OpRethConfig::default() + .set_trusted_peers(vec![l2_enode]) + .set_genesis(genesis_str) + .build()? + .with_mapped_port(builder_p2p_port, ContainerPort::Tcp(P2P_PORT)) + .with_mapped_port(builder_p2p_port, ContainerPort::Udp(P2P_PORT)) + .with_mapped_port(get_available_port(), ContainerPort::Tcp(AUTH_RPC_PORT)) + .with_network(&network) + .with_log_consumer(builder_log_consumer) + .start() + .await?; + + Builder::Reth(builder) + }; println!("l2 authrpc: {}", l2.auth_rpc().await?); println!("builder authrpc: {}", builder.auth_rpc().await?); diff --git a/crates/rollup-boost/src/tests/common/services/mod.rs b/crates/rollup-boost/src/tests/common/services/mod.rs index 41ef9049..e2783873 100644 --- a/crates/rollup-boost/src/tests/common/services/mod.rs +++ b/crates/rollup-boost/src/tests/common/services/mod.rs @@ -1,2 +1,3 @@ +pub mod op_rbuilder; pub mod op_reth; pub mod rollup_boost; diff --git a/crates/rollup-boost/src/tests/common/services/op_rbuilder.rs b/crates/rollup-boost/src/tests/common/services/op_rbuilder.rs new file mode 100644 index 00000000..3e3d546e --- /dev/null +++ b/crates/rollup-boost/src/tests/common/services/op_rbuilder.rs @@ -0,0 +1,206 @@ +use http::Uri; +use std::{borrow::Cow, collections::HashMap, path::PathBuf}; +use testcontainers::{ + ContainerAsync, CopyToContainer, Image, + core::{ContainerPort, WaitFor}, +}; + +use crate::tests::common::TEST_DATA; + +const NAME: &str = "ghcr.io/flashbots/op-rbuilder"; +const TAG: &str = "sha-4f1931b"; // temporal + +pub const AUTH_RPC_PORT: u16 = 8551; +pub const P2P_PORT: u16 = 30303; +pub const FLASHBLOCKS_PORT: u16 = 1112; + +#[derive(Debug, Clone)] +pub struct OpRbuilderConfig { + jwt_secret: PathBuf, + p2p_secret: Option, + pub trusted_peers: Vec, + pub color: String, + pub ipcdisable: bool, + pub env_vars: HashMap, + pub genesis: Option, + flashblocks: bool, +} + +impl Default for OpRbuilderConfig { + fn default() -> Self { + Self { + jwt_secret: PathBuf::from(format!("{}/jwt_secret.hex", *TEST_DATA)), + p2p_secret: None, + trusted_peers: vec![], + color: "never".to_string(), + ipcdisable: true, + env_vars: Default::default(), + genesis: None, + flashblocks: false, + } + } +} + +impl OpRbuilderConfig { + pub fn set_trusted_peers(mut self, trusted_peers: Vec) -> Self { + self.trusted_peers = trusted_peers; + self + } + + pub fn set_jwt_secret(mut self, jwt_secret: PathBuf) -> Self { + self.jwt_secret = jwt_secret; + self + } + + pub fn set_p2p_secret(mut self, p2p_secret: Option) -> Self { + self.p2p_secret = p2p_secret; + self + } + + pub fn set_genesis(mut self, genesis: String) -> Self { + self.genesis = Some(genesis); + self + } + + pub fn set_flashblocks(mut self, flashblocks: bool) -> Self { + self.flashblocks = flashblocks; + self + } + + pub fn build(self) -> eyre::Result { + let genesis = self + .genesis + .clone() + .ok_or_else(|| eyre::eyre!("Genesis configuration not found"))?; + + let mut copy_to_sources = vec![ + CopyToContainer::new( + std::fs::read_to_string(&self.jwt_secret)?.into_bytes(), + "/jwt_secret.hex".to_string(), + ), + CopyToContainer::new(genesis.into_bytes(), "/genesis.json".to_string()), + ]; + + if let Some(p2p_secret) = &self.p2p_secret { + let p2p_string = std::fs::read_to_string(p2p_secret) + .unwrap() + .replace("\n", ""); + copy_to_sources.push(CopyToContainer::new( + p2p_string.into_bytes(), + "/p2p_secret.hex".to_string(), + )); + } + + let expose_ports = vec![]; + + Ok(OpRbuilderImage { + config: self, + copy_to_sources, + expose_ports, + }) + } +} + +impl OpRbuilderImage { + pub fn config(&self) -> &OpRbuilderConfig { + &self.config + } +} + +#[derive(Debug, Clone)] +pub struct OpRbuilderImage { + config: OpRbuilderConfig, + copy_to_sources: Vec, + expose_ports: Vec, +} + +impl Image for OpRbuilderImage { + fn name(&self) -> &str { + NAME + } + + fn tag(&self) -> &str { + TAG + } + + fn ready_conditions(&self) -> Vec { + vec![WaitFor::message_on_stdout("Starting consensus")] + } + + fn env_vars( + &self, + ) -> impl IntoIterator>, impl Into>)> { + &self.config.env_vars + } + + fn copy_to_sources(&self) -> impl IntoIterator { + self.copy_to_sources.iter() + } + + fn cmd(&self) -> impl IntoIterator>> { + let mut cmd = vec![ + "node".to_string(), + "--port=30303".to_string(), + "--addr=0.0.0.0".to_string(), + "--http".to_string(), + "--http.addr=0.0.0.0".to_string(), + "--http.api=eth,net,web3,debug,miner".to_string(), + "--authrpc.port=8551".to_string(), + "--authrpc.addr=0.0.0.0".to_string(), + "--authrpc.jwtsecret=/jwt_secret.hex".to_string(), + "--chain=/genesis.json".to_string(), + "-vvv".to_string(), + "--disable-discovery".to_string(), + "--color".to_string(), + self.config.color.clone(), + ]; + if self.config.flashblocks { + cmd.extend([ + "--flashblocks.enabled".to_string(), + "--flashblocks.addr=0.0.0.0".to_string(), + "--flashblocks.port=1112".to_string(), + ]); + } + if self.config.p2p_secret.is_some() { + cmd.push("--p2p-secret-key=/p2p_secret.hex".to_string()); + } + if !self.config.trusted_peers.is_empty() { + println!("Trusted peers: {:?}", self.config.trusted_peers); + cmd.extend([ + "--trusted-peers".to_string(), + self.config.trusted_peers.join(","), + ]); + } + if self.config.ipcdisable { + cmd.push("--ipcdisable".to_string()); + } + + println!("cmd: {}", cmd.join(" ")); + + cmd + } + + fn expose_ports(&self) -> &[ContainerPort] { + &self.expose_ports + } +} + +pub trait OpRbuilderMehods { + async fn auth_rpc(&self) -> eyre::Result; + async fn auth_rpc_port(&self) -> eyre::Result; +} + +impl OpRbuilderMehods for ContainerAsync { + async fn auth_rpc_port(&self) -> eyre::Result { + Ok(self.get_host_port_ipv4(AUTH_RPC_PORT).await?) + } + + async fn auth_rpc(&self) -> eyre::Result { + Ok(format!( + "http://{}:{}", + self.get_host().await?, + self.get_host_port_ipv4(AUTH_RPC_PORT).await? + ) + .parse()?) + } +} diff --git a/crates/rollup-boost/src/tests/flashblocks.rs b/crates/rollup-boost/src/tests/flashblocks.rs new file mode 100644 index 00000000..9a1dccbd --- /dev/null +++ b/crates/rollup-boost/src/tests/flashblocks.rs @@ -0,0 +1,14 @@ +use super::common::RollupBoostTestHarnessBuilder; + +#[tokio::test] +async fn test_integration_flashblocks_simple() -> eyre::Result<()> { + let harness = RollupBoostTestHarnessBuilder::new("flashblocks_simple") + .with_flashblocks(true) + .with_isthmus_block(0) + .build() + .await?; + let mut block_generator = harness.block_generator().await?; + block_generator.generate_builder_blocks(10).await?; + + Ok(()) +} diff --git a/crates/rollup-boost/src/tests/mod.rs b/crates/rollup-boost/src/tests/mod.rs index 6a4d924e..a33cd630 100644 --- a/crates/rollup-boost/src/tests/mod.rs +++ b/crates/rollup-boost/src/tests/mod.rs @@ -4,6 +4,7 @@ mod builder_full_delay; mod builder_returns_incorrect_block; mod execution_mode; mod fcu_no_block_time_delay; +mod flashblocks; mod no_tx_pool; mod remote_builder_down; mod simple;