From 35126e3799635cb3117ca9c94e71dc170ba6f3e2 Mon Sep 17 00:00:00 2001 From: James Date: Wed, 12 Nov 2025 14:34:37 -0500 Subject: [PATCH] feat: add a couple checks to the env task --- bin/builder.rs | 4 ++- src/macros.rs | 10 +++++- src/quincey.rs | 39 +++++++++++++++++++++++- src/tasks/env.rs | 61 ++++++++++++++++++++++++++----------- tests/block_builder_test.rs | 5 ++- tests/cache.rs | 1 + tests/env.rs | 2 ++ 7 files changed, 101 insertions(+), 21 deletions(-) diff --git a/bin/builder.rs b/bin/builder.rs index 011e71e..1058849 100644 --- a/bin/builder.rs +++ b/bin/builder.rs @@ -26,9 +26,11 @@ async fn main() -> eyre::Result<()> { // RU WS connection is invalid. let (ru_provider, host_provider) = tokio::try_join!(config.connect_ru_provider(), config.connect_host_provider(),)?; + let quincey = config.connect_quincey().await?; // Spawn the EnvTask - let env_task = EnvTask::new(config.clone(), host_provider.clone(), ru_provider.clone()); + let env_task = + EnvTask::new(config.clone(), host_provider.clone(), quincey, ru_provider.clone()); let (block_env, env_jh) = env_task.spawn(); // Spawn the cache system diff --git a/src/macros.rs b/src/macros.rs index ccc2950..9718794 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -24,6 +24,14 @@ macro_rules! span_info { } +/// Helper macro to log a warning event within a span that is not currently +/// entered. +macro_rules! span_warn { + ($span:expr, $($arg:tt)*) => { + span_scoped!($span, warn!($($arg)*)) + }; +} + /// Helper macro to log a warning event within a span that is not currently /// entered. macro_rules! span_error { @@ -34,7 +42,7 @@ macro_rules! span_error { /// Helper macro to unwrap a result or continue the loop with a tracing event. macro_rules! res_unwrap_or_continue { - ($result:expr, $span:expr, $level:ident!($($arg:tt)*)) => { + ($result:expr, $span:expr, $level:ident!($($arg:tt)*) $(,)?) => { match $result { Ok(value) => value, Err(err) => { diff --git a/src/quincey.rs b/src/quincey.rs index 862c82d..eab5262 100644 --- a/src/quincey.rs +++ b/src/quincey.rs @@ -1,7 +1,11 @@ -use alloy::signers::Signer; +use alloy::{ + primitives::{Address, B256, U256}, + signers::Signer, +}; use eyre::bail; use init4_bin_base::{perms::SharedToken, utils::signer::LocalOrAws}; use reqwest::Client; +use signet_constants::SignetSystemConstants; use signet_types::{SignRequest, SignResponse}; use tracing::{debug, info, instrument, trace}; @@ -35,6 +39,16 @@ impl Quincey { Self::Owned(client) } + /// Returns `true` if the signer is local. + pub const fn is_local(&self) -> bool { + matches!(self, Self::Owned(_)) + } + + /// Returns `true` if the signer is remote. + pub const fn is_remote(&self) -> bool { + matches!(self, Self::Remote { .. }) + } + async fn sup_owned(&self, sig_request: &SignRequest) -> eyre::Result { let Self::Owned(signer) = &self else { eyre::bail!("not an owned client") }; @@ -77,4 +91,27 @@ impl Quincey { Self::Remote { .. } => self.sup_remote(sig_request).await, } } + + /// Perform a preflight check to ensure that the Quincey service will + /// be able to sign a request with the provided parameters at this + /// point in time. + #[instrument(skip(self, constants))] + pub async fn preflight_check( + &self, + constants: &SignetSystemConstants, + host_block_number: u64, + ) -> eyre::Result<()> { + if self.is_local() { + return Ok(()); + } + let req = SignRequest { + host_block_number: U256::from(host_block_number), + host_chain_id: U256::from(constants.host_chain_id()), + ru_chain_id: U256::from(constants.ru_chain_id()), + gas_limit: U256::ZERO, + ru_reward_address: Address::ZERO, + contents: B256::ZERO, + }; + self.sup_remote(&req).await.map(|_| ()) + } } diff --git a/src/tasks/env.rs b/src/tasks/env.rs index 0584013..c5be9fa 100644 --- a/src/tasks/env.rs +++ b/src/tasks/env.rs @@ -1,5 +1,6 @@ use crate::{ config::{BuilderConfig, HostProvider, RuProvider}, + quincey::Quincey, tasks::block::cfg::SignetCfgEnv, }; use alloy::{ @@ -31,21 +32,6 @@ pub type SimRollupEnv = RollupEnv; /// Type aliases for simulation environments. pub type SimHostEnv = HostEnv; -/// A task that constructs a BlockEnv for the next block in the rollup chain. -#[derive(Debug, Clone)] -pub struct EnvTask { - /// Builder configuration values. - config: BuilderConfig, - - /// Host provider is used to get the latest host block header for - /// constructing the next block environment. - host_provider: HostProvider, - - /// Rollup provider is used to get the latest rollup block header for - /// simulation. - ru_provider: RuProvider, -} - /// An environment for simulating a block. #[derive(Debug, Clone)] pub struct Environment { @@ -196,14 +182,33 @@ impl SimEnv { } } +/// A task that constructs a BlockEnv for the next block in the rollup chain. +#[derive(Debug, Clone)] +pub struct EnvTask { + /// Builder configuration values. + config: BuilderConfig, + + /// Host provider is used to get the latest host block header for + /// constructing the next block environment. + host_provider: HostProvider, + + /// Quincey instance for slot checking. + quincey: Quincey, + + /// Rollup provider is used to get the latest rollup block header for + /// simulation. + ru_provider: RuProvider, +} + impl EnvTask { /// Create a new [`EnvTask`] with the given config and providers. pub const fn new( config: BuilderConfig, host_provider: HostProvider, + quincey: Quincey, ru_provider: RuProvider, ) -> Self { - Self { config, host_provider, ru_provider } + Self { config, host_provider, quincey, ru_provider } } /// Construct a [`BlockEnv`] for the next host block from the previous host header. @@ -271,11 +276,23 @@ impl EnvTask { let span = info_span!("SimEnv", %host_block_number, %rollup_header.hash, %rollup_header.number); + let (host_block_res, quincey_res) = tokio::join!( + self.host_provider.get_block_by_number(host_block_number.into()), + self.quincey.preflight_check(&self.config.constants, host_block_number) + ); + + res_unwrap_or_continue!( + quincey_res, + span, + error!("error checking quincey slot - skipping block submission"), + ); + let host_block_opt = res_unwrap_or_continue!( - self.host_provider.get_block_by_number(host_block_number.into()).await, + host_block_res, span, error!("error fetching previous host block - skipping block submission") ); + let host_header = opt_unwrap_or_continue!( host_block_opt, span, @@ -284,6 +301,16 @@ impl EnvTask { .header .inner; + if rollup_header.timestamp != host_header.timestamp { + span_warn!( + span, + rollup_timestamp = rollup_header.timestamp, + host_timestamp = host_header.timestamp, + "rollup block timestamp differs from host block timestamp. - skipping block submission" + ); + continue; + } + // Construct the block env using the previous block header let rollup_env = self.construct_rollup_env(rollup_header.into()); let host_env = self.construct_host_env(host_header); diff --git a/tests/block_builder_test.rs b/tests/block_builder_test.rs index 92adfef..a45e4a6 100644 --- a/tests/block_builder_test.rs +++ b/tests/block_builder_test.rs @@ -43,8 +43,11 @@ async fn test_handle_build() { let ru_provider = RootProvider::::new_http(anvil_instance.endpoint_url()); let host_provider = config.connect_host_provider().await.unwrap(); + // Create a quincey client + let quincey = config.connect_quincey().await.unwrap(); + let block_env = - EnvTask::new(config.clone(), host_provider.clone(), ru_provider.clone()).spawn().0; + EnvTask::new(config.clone(), host_provider.clone(), quincey, ru_provider.clone()).spawn().0; let block_builder = Simulator::new(&config, host_provider.clone(), ru_provider.clone(), block_env); diff --git a/tests/cache.rs b/tests/cache.rs index c306f05..d975fca 100644 --- a/tests/cache.rs +++ b/tests/cache.rs @@ -15,6 +15,7 @@ async fn test_bundle_poller_roundtrip() -> eyre::Result<()> { let (block_env, _jh) = EnvTask::new( config.clone(), config.connect_host_provider().await?, + config.connect_quincey().await?, config.connect_ru_provider().await?, ) .spawn(); diff --git a/tests/env.rs b/tests/env.rs index 735a28d..634b459 100644 --- a/tests/env.rs +++ b/tests/env.rs @@ -9,9 +9,11 @@ async fn test_bundle_poller_roundtrip() -> eyre::Result<()> { setup_logging(); let config = setup_test_config().unwrap(); + let (mut env_watcher, _jh) = EnvTask::new( config.clone(), config.connect_host_provider().await?, + config.connect_quincey().await?, config.connect_ru_provider().await?, ) .spawn();