diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index ddd659d6..f2cb5316 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -111,7 +111,7 @@ jobs: run: builder-playground & - name: Run integration tests with flags - run: cargo test --features="${{ matrix.features }}" --package rbuilder --lib -- integration + run: cargo test --features="${{ matrix.features }}" --package rbuilder --lib -- integration --test-threads=1 env: PLAYGROUND: TRUE diff --git a/crates/rbuilder/src/integration/playground.rs b/crates/rbuilder/src/integration/playground.rs index e9b79c86..0468c149 100644 --- a/crates/rbuilder/src/integration/playground.rs +++ b/crates/rbuilder/src/integration/playground.rs @@ -42,15 +42,11 @@ fn open_log_file(path: PathBuf) -> io::Result { } impl Playground { - pub fn new() -> Result { + pub fn new(cfg_path: &PathBuf) -> Result { // load the binary from the cargo_dir let mut bin_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); bin_path.push("../../target/debug/rbuilder"); - // Use the config file from the root directory - let config_path = - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../config-playground.toml"); - let dt: OffsetDateTime = SystemTime::now().into(); let format = format_description::parse("[year]_[month]_[day]_[hour]_[minute]_[second]") @@ -68,7 +64,7 @@ impl Playground { let mut cmd = Command::new(bin_path.clone()); - cmd.arg("run").arg(config_path); + cmd.arg("run").arg(cfg_path); cmd.stdout(stdout).stderr(stderr); let builder = match cmd.spawn() { @@ -102,6 +98,10 @@ impl Playground { Ok(Self { builder }) } + pub fn builder_is_alive(&mut self) -> bool { + matches!(self.builder.try_wait(), Ok(None)) + } + pub async fn wait_for_next_slot( &self, ) -> Result> { diff --git a/crates/rbuilder/src/integration/simple.rs b/crates/rbuilder/src/integration/simple.rs index bcb20792..f5d06117 100644 --- a/crates/rbuilder/src/integration/simple.rs +++ b/crates/rbuilder/src/integration/simple.rs @@ -1,20 +1,25 @@ #[cfg(test)] mod tests { - use crate::integration::playground::Playground; + use crate::{ + integration::playground::Playground, + live_builder::block_list_provider::test::{BlocklistHttpServer, BLOCKLIST_LEN_2}, + }; use alloy_network::TransactionBuilder; use alloy_primitives::U256; use alloy_provider::{PendingTransactionBuilder, Provider, ProviderBuilder}; use alloy_rpc_types::TransactionRequest; - use std::str::FromStr; + use std::{path::PathBuf, str::FromStr, time::Duration}; use test_utils::ignore_if_env_not_set; use url::Url; - #[ignore_if_env_not_set("PLAYGROUND")] // TODO: Change with a custom macro (i.e ignore_if_not_playground) #[tokio::test] async fn test_simple_example() { + let config_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("../../crates/rbuilder/src/integration/test_data/config-playground.toml"); + // This test sends a transaction ONLY to the builder and waits for the block to be built with it. - let srv = Playground::new().unwrap(); + let srv = Playground::new(&config_path).unwrap(); srv.wait_for_next_slot().await.unwrap(); // send a transfer to the builder @@ -52,4 +57,26 @@ mod tests { .await .unwrap(); } + + #[ignore_if_env_not_set("PLAYGROUND")] + /// TODO: Change with a custom macro (i.e ignore_if_not_playground) + /// Sadly builder shutdown does not always work properly so we have to wait for the watchdog to kill the process. + #[tokio::test] + async fn test_builder_closes_on_old_blocklist() { + let config_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join( + "../../crates/rbuilder/src/integration/test_data/config-playground-http-blocklist.toml", + ); + let blocklist_server = BlocklistHttpServer::new(1934, Some(BLOCKLIST_LEN_2.to_string())); + tokio::time::sleep(Duration::from_millis(100)).await; //puaj + let mut srv = Playground::new(&config_path).unwrap(); + srv.wait_for_next_slot().await.unwrap(); + blocklist_server.set_answer(None); + let timeout_secs = 5 /*blocklist_url_max_age_secs in cfg */ + + 12 /* problem detected in next block start an cancel is signaled*/+ + 15 /*watchdog_timeout_sec */+ + 12 /*extra delay from watchdog*/+ + 1 /* for timing errors */; + tokio::time::sleep(Duration::from_secs(timeout_secs)).await; //puaj + assert!(!srv.builder_is_alive()); + } } diff --git a/crates/rbuilder/src/integration/test_data/config-playground-http-blocklist.toml b/crates/rbuilder/src/integration/test_data/config-playground-http-blocklist.toml new file mode 100644 index 00000000..4e5f0dd4 --- /dev/null +++ b/crates/rbuilder/src/integration/test_data/config-playground-http-blocklist.toml @@ -0,0 +1,12 @@ + +chain = "$HOME/.playground/devnet/genesis.json" +reth_datadir = "$HOME/.playground/devnet/data_reth" +relay_secret_key = "5eae315483f028b5cdd5d1090ff0c7618b18737ea9bf3c35047189db22835c48" +el_node_ipc_path = "$HOME/.playground/devnet/reth.ipc" +live_builders = ["mgp-ordering"] +enabled_relays = ["playground"] +log_level = "info,rbuilder=debug" +coinbase_secret_key = "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" +blocklist_url_max_age_secs = 5 +watchdog_timeout_sec = 15 +blocklist = "http://127.0.0.1:1934" \ No newline at end of file diff --git a/crates/rbuilder/src/integration/test_data/config-playground.toml b/crates/rbuilder/src/integration/test_data/config-playground.toml new file mode 100644 index 00000000..68080538 --- /dev/null +++ b/crates/rbuilder/src/integration/test_data/config-playground.toml @@ -0,0 +1,9 @@ + +chain = "$HOME/.playground/devnet/genesis.json" +reth_datadir = "$HOME/.playground/devnet/data_reth" +relay_secret_key = "5eae315483f028b5cdd5d1090ff0c7618b18737ea9bf3c35047189db22835c48" +el_node_ipc_path = "$HOME/.playground/devnet/reth.ipc" +live_builders = ["mgp-ordering"] +enabled_relays = ["playground"] +log_level = "info,rbuilder=debug" +coinbase_secret_key = "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" diff --git a/crates/rbuilder/src/live_builder/base_config.rs b/crates/rbuilder/src/live_builder/base_config.rs index 99cadff5..d68fa302 100644 --- a/crates/rbuilder/src/live_builder/base_config.rs +++ b/crates/rbuilder/src/live_builder/base_config.rs @@ -99,6 +99,9 @@ pub struct BaseConfig { /// If the downloaded file get older than this we abort. pub blocklist_url_max_age_hours: Option, + /// Like blocklist_url_max_age_hours but in secs for integration tests. + pub blocklist_url_max_age_secs: Option, + #[serde(deserialize_with = "deserialize_extra_data")] pub extra_data: Vec, @@ -346,11 +349,15 @@ impl BaseConfig { validate_blocklist: bool, cancellation_token: tokio_util::sync::CancellationToken, ) -> eyre::Result> { - let max_allowed_age_hours = self - .blocklist_url_max_age_hours - .unwrap_or(DEFAULT_BLOCKLIST_URL_MAX_AGE_HOURS); - let max_allowed_age = - Duration::from_secs(max_allowed_age_hours * SECS_PER_MINUTE * MINS_PER_HOUR); + let max_allowed_age_secs = + if let Some(max_allowed_age_hours) = self.blocklist_url_max_age_hours { + max_allowed_age_hours * SECS_PER_MINUTE * MINS_PER_HOUR + } else if let Some(blocklist_url_max_age_secs) = self.blocklist_url_max_age_secs { + blocklist_url_max_age_secs + } else { + DEFAULT_BLOCKLIST_URL_MAX_AGE_HOURS * SECS_PER_MINUTE * MINS_PER_HOUR + }; + let max_allowed_age = Duration::from_secs(max_allowed_age_secs); let provider = HttpBlockListProvider::new( blocklist_url, max_allowed_age, @@ -487,6 +494,7 @@ impl Default for BaseConfig { blocklist_file_path: None, blocklist: None, blocklist_url_max_age_hours: None, + blocklist_url_max_age_secs: None, extra_data: b"extra_data_change_me".to_vec(), root_hash_use_sparse_trie: false, root_hash_compare_sparse_trie: false, diff --git a/crates/rbuilder/src/live_builder/block_list_provider.rs b/crates/rbuilder/src/live_builder/block_list_provider.rs index d9c76368..ce3c592f 100644 --- a/crates/rbuilder/src/live_builder/block_list_provider.rs +++ b/crates/rbuilder/src/live_builder/block_list_provider.rs @@ -229,7 +229,7 @@ pub fn blocklist_hash(blocklist: &BlockList) -> B256 { } #[cfg(test)] -mod test { +pub mod test { use std::{ io::{Read, Write}, net::{TcpListener, TcpStream}, @@ -257,7 +257,7 @@ mod test { assert_eq!(exected_hash, hash); } - struct BlocklistHttpServer { + pub struct BlocklistHttpServer { /// None -> returns 404 error answer: Mutex>, } @@ -325,7 +325,7 @@ mod test { lazy_static! { static ref BLOCKLIST_LEN_1: String = "[\"".to_string() + BLOCKED_ADDRESS + "\"]"; } - const BLOCKLIST_LEN_2: &str = r#"["0x03893a7c7463AE47D46bc7f091665f1893656003","0x01e2919679362dFBC9ee1644Ba9C6da6D6245BB1"]"#; + pub const BLOCKLIST_LEN_2: &str = r#"["0x03893a7c7463AE47D46bc7f091665f1893656003","0x01e2919679362dFBC9ee1644Ba9C6da6D6245BB1"]"#; const EMPTY_BLOCKLIST: &str = r#"[]"#; #[tokio::test]