diff --git a/crates/op-rbuilder/src/args/op.rs b/crates/op-rbuilder/src/args/op.rs index b0b90f84..1d81c382 100644 --- a/crates/op-rbuilder/src/args/op.rs +++ b/crates/op-rbuilder/src/args/op.rs @@ -167,6 +167,15 @@ pub struct FlashblocksArgs { )] pub flashblocks_number_contract_address: Option
, + /// Use permit signatures if flashtestations is enabled with the flashtestation key + /// to increment the flashblocks number + #[arg( + long = "flashblocks.number-contract-use-permit", + env = "FLASHBLOCK_NUMBER_CONTRACT_USE_PERMIT", + default_value = "false" + )] + pub flashblocks_number_contract_use_permit: bool, + /// Flashblocks p2p configuration #[command(flatten)] pub p2p: FlashblocksP2pArgs, diff --git a/crates/op-rbuilder/src/builders/builder_tx.rs b/crates/op-rbuilder/src/builders/builder_tx.rs index 11194a38..7cc56b07 100644 --- a/crates/op-rbuilder/src/builders/builder_tx.rs +++ b/crates/op-rbuilder/src/builders/builder_tx.rs @@ -126,7 +126,7 @@ impl From for PayloadBuilderError { BuilderTransactionError::EvmExecutionError(e) => { PayloadBuilderError::EvmExecutionError(e) } - _ => PayloadBuilderError::Other(Box::new(error)), + _ => PayloadBuilderError::other(error), } } } diff --git a/crates/op-rbuilder/src/builders/flashblocks/builder_tx.rs b/crates/op-rbuilder/src/builders/flashblocks/builder_tx.rs index 04afc64d..da32fbcb 100644 --- a/crates/op-rbuilder/src/builders/flashblocks/builder_tx.rs +++ b/crates/op-rbuilder/src/builders/flashblocks/builder_tx.rs @@ -1,31 +1,25 @@ -use alloy_consensus::TxEip1559; use alloy_eips::Encodable2718; use alloy_evm::{Database, Evm}; use alloy_op_evm::OpEvm; -use alloy_primitives::{Address, TxKind}; -use alloy_sol_types::{Error, SolCall, SolEvent, SolInterface, sol}; +use alloy_primitives::{Address, B256, Signature, U256}; +use alloy_rpc_types_eth::TransactionInput; +use alloy_sol_types::{SolCall, SolEvent, sol}; use core::fmt::Debug; -use op_alloy_consensus::OpTypedTransaction; -use op_revm::OpHaltReason; +use op_alloy_rpc_types::OpTransactionRequest; use reth_evm::{ConfigureEvm, precompiles::PrecompilesMap}; -use reth_optimism_primitives::OpTransactionSigned; -use reth_primitives::Recovered; use reth_provider::StateProvider; use reth_revm::State; -use revm::{ - DatabaseRef, - context::result::{ExecutionResult, ResultAndState}, - inspector::NoOpInspector, -}; +use revm::{DatabaseRef, inspector::NoOpInspector}; use tracing::warn; use crate::{ builders::{ BuilderTransactionCtx, BuilderTransactionError, BuilderTransactions, - InvalidContractDataError, - builder_tx::{BuilderTxBase, get_nonce}, + SimulationSuccessResult, + builder_tx::BuilderTxBase, context::OpPayloadBuilderCtx, flashblocks::payload::{FlashblocksExecutionInfo, FlashblocksExtraCtx}, + get_nonce, }, flashtestations::builder_tx::FlashtestationsBuilderTx, primitives::reth::ExecutionInfo, @@ -37,8 +31,17 @@ sol!( #[sol(rpc, abi)] #[derive(Debug)] interface IFlashblockNumber { + uint256 public flashblockNumber; + function incrementFlashblockNumber() external; + function permitIncrementFlashblockNumber(uint256 currentFlashblockNumber, bytes memory signature) external; + + function computeStructHash(uint256 currentFlashblockNumber) external pure returns (bytes32); + + function hashTypedDataV4(bytes32 structHash) external view returns (bytes32); + + // @notice Emitted when flashblock index is incremented // @param newFlashblockIndex The new flashblock index (0-indexed within each L2 block) event FlashblockIncremented(uint256 newFlashblockIndex); @@ -51,16 +54,6 @@ sol!( } ); -#[derive(Debug, thiserror::Error)] -pub(super) enum FlashblockNumberError { - #[error("flashblocks number contract tx reverted: {0:?}")] - Revert(IFlashblockNumber::IFlashblockNumberErrors), - #[error("unknown revert: {0} err: {1}")] - Unknown(String, Error), - #[error("halt: {0:?}")] - Halt(OpHaltReason), -} - // This will be the end of block transaction of a regular block #[derive(Debug, Clone)] pub(super) struct FlashblocksBuilderTx { @@ -133,8 +126,9 @@ impl BuilderTransactions for Flas // This will be the end of block transaction of a regular block #[derive(Debug, Clone)] pub(super) struct FlashblocksNumberBuilderTx { - pub signer: Option, + pub signer: Signer, pub flashblock_number_address: Address, + pub use_permit: bool, pub base_builder_tx: BuilderTxBase, pub flashtestations_builder_tx: Option>, @@ -142,85 +136,129 @@ pub(super) struct FlashblocksNumberBuilderTx { impl FlashblocksNumberBuilderTx { pub(super) fn new( - signer: Option, + signer: Signer, flashblock_number_address: Address, + use_permit: bool, flashtestations_builder_tx: Option< FlashtestationsBuilderTx, >, ) -> Self { - let base_builder_tx = BuilderTxBase::new(signer); + let base_builder_tx = BuilderTxBase::new(Some(signer)); Self { signer, flashblock_number_address, + use_permit, base_builder_tx, flashtestations_builder_tx, } } - // TODO: remove and clean up in favour of simulate_call() - fn estimate_flashblock_number_tx_gas( + fn signed_increment_flashblocks_tx( &self, ctx: &OpPayloadBuilderCtx, - evm: &mut OpEvm, - signer: &Signer, - nonce: u64, - ) -> Result { - let tx = self.signed_flashblock_number_tx(ctx, ctx.block_gas_limit(), nonce, signer)?; - let ResultAndState { result, .. } = match evm.transact(&tx) { - Ok(res) => res, - Err(err) => { - return Err(BuilderTransactionError::EvmExecutionError(Box::new(err))); - } - }; + evm: &mut OpEvm, + ) -> Result { + let calldata = IFlashblockNumber::incrementFlashblockNumberCall {}; + self.increment_flashblocks_tx(calldata, &self.signer, ctx, evm) + } - match result { - ExecutionResult::Success { gas_used, logs, .. } => { - if logs.iter().any(|log| { - log.topics().first() - == Some(&IFlashblockNumber::FlashblockIncremented::SIGNATURE_HASH) - }) { - Ok(gas_used) - } else { - Err(BuilderTransactionError::InvalidContract( - self.flashblock_number_address, - InvalidContractDataError::InvalidLogs( - vec![IFlashblockNumber::FlashblockIncremented::SIGNATURE_HASH], - vec![], - ), - )) - } - } - ExecutionResult::Revert { output, .. } => Err(BuilderTransactionError::other( - IFlashblockNumber::IFlashblockNumberErrors::abi_decode(&output) - .map(FlashblockNumberError::Revert) - .unwrap_or_else(|e| FlashblockNumberError::Unknown(hex::encode(output), e)), - )), - ExecutionResult::Halt { reason, .. } => Err(BuilderTransactionError::other( - FlashblockNumberError::Halt(reason), - )), - } + fn increment_flashblocks_permit_signature( + &self, + flashtestations_signer: &Signer, + current_flashblock_number: U256, + ctx: &OpPayloadBuilderCtx, + evm: &mut OpEvm, + ) -> Result { + let struct_hash_calldata = IFlashblockNumber::computeStructHashCall { + currentFlashblockNumber: current_flashblock_number, + }; + let SimulationSuccessResult { output, .. } = + self.simulate_flashblocks_readonly_call(struct_hash_calldata, ctx, evm)?; + let typed_data_hash_calldata = + IFlashblockNumber::hashTypedDataV4Call { structHash: output }; + let SimulationSuccessResult { output, .. } = + self.simulate_flashblocks_readonly_call(typed_data_hash_calldata, ctx, evm)?; + let signature = flashtestations_signer.sign_message(output)?; + Ok(signature) } - fn signed_flashblock_number_tx( + fn signed_increment_flashblocks_permit_tx( &self, + flashtestations_signer: &Signer, ctx: &OpPayloadBuilderCtx, - gas_limit: u64, - nonce: u64, + evm: &mut OpEvm, + ) -> Result { + let current_flashblock_calldata = IFlashblockNumber::flashblockNumberCall {}; + let SimulationSuccessResult { output, .. } = + self.simulate_flashblocks_readonly_call(current_flashblock_calldata, ctx, evm)?; + let signature = + self.increment_flashblocks_permit_signature(flashtestations_signer, output, ctx, evm)?; + let calldata = IFlashblockNumber::permitIncrementFlashblockNumberCall { + currentFlashblockNumber: output, + signature: signature.as_bytes().into(), + }; + self.increment_flashblocks_tx(calldata, flashtestations_signer, ctx, evm) + } + + fn increment_flashblocks_tx( + &self, + calldata: T, signer: &Signer, - ) -> Result, secp256k1::Error> { - let calldata = IFlashblockNumber::incrementFlashblockNumberCall {}.abi_encode(); - // Create the EIP-1559 transaction - let tx = OpTypedTransaction::Eip1559(TxEip1559 { - chain_id: ctx.chain_id(), - nonce, - gas_limit, - max_fee_per_gas: ctx.base_fee().into(), - max_priority_fee_per_gas: 0, - to: TxKind::Call(self.flashblock_number_address), - input: calldata.into(), - ..Default::default() - }); - signer.sign_tx(tx) + ctx: &OpPayloadBuilderCtx, + evm: &mut OpEvm, + ) -> Result { + let SimulationSuccessResult { gas_used, .. } = self.simulate_flashblocks_call( + calldata.clone(), + vec![IFlashblockNumber::FlashblockIncremented::SIGNATURE_HASH], + ctx, + evm, + )?; + let signed_tx = self.sign_tx( + self.flashblock_number_address, + *signer, + gas_used, + calldata.abi_encode().into(), + ctx, + evm.db_mut(), + )?; + let da_size = + op_alloy_flz::tx_estimated_size_fjord_bytes(signed_tx.encoded_2718().as_slice()); + Ok(BuilderTransactionCtx { + signed_tx, + gas_used, + da_size, + is_top_of_block: true, + }) + } + + fn simulate_flashblocks_readonly_call( + &self, + calldata: T, + ctx: &OpPayloadBuilderCtx, + evm: &mut OpEvm, + ) -> Result, BuilderTransactionError> { + self.simulate_flashblocks_call(calldata, vec![], ctx, evm) + } + + fn simulate_flashblocks_call( + &self, + calldata: T, + expected_logs: Vec, + ctx: &OpPayloadBuilderCtx, + evm: &mut OpEvm, + ) -> Result, BuilderTransactionError> { + let tx_req = OpTransactionRequest::default() + .gas_limit(ctx.block_gas_limit()) + .max_fee_per_gas(ctx.base_fee().into()) + .to(self.flashblock_number_address) + .from(self.signer.address) // use tee key as signer for simulations + .nonce(get_nonce(evm.db(), self.signer.address)?) + .input(TransactionInput::new(calldata.abi_encode().into())); + self.simulate_call::( + tx_req, + expected_logs, + evm, + ) } } @@ -242,46 +280,35 @@ impl BuilderTransactions builder_txs.extend(self.base_builder_tx.simulate_builder_tx(ctx, &mut *db)?); } else { // we increment the flashblock number for the next flashblock so we don't increment in the last flashblock - if let Some(signer) = &self.signer { - let mut evm = ctx.evm_config.evm_with_env(&mut *db, ctx.evm_env.clone()); - evm.modify_cfg(|cfg| { - cfg.disable_balance_check = true; - cfg.disable_block_gas_limit = true; - }); + let mut evm = ctx.evm_config.evm_with_env(&mut *db, ctx.evm_env.clone()); + evm.modify_cfg(|cfg| { + cfg.disable_balance_check = true; + cfg.disable_block_gas_limit = true; + }); - let nonce = get_nonce(evm.db_mut(), signer.address)?; - - let tx = match self.estimate_flashblock_number_tx_gas(ctx, &mut evm, signer, nonce) - { - Ok(gas_used) => { - // Due to EIP-150, 63/64 of available gas is forwarded to external calls so need to add a buffer - let signed_tx = self.signed_flashblock_number_tx( - ctx, - gas_used * 64 / 63, - nonce, - signer, - )?; + let flashblocks_num_tx = if let Some(flashtestations) = &self.flashtestations_builder_tx + && self.use_permit + { + self.signed_increment_flashblocks_permit_tx( + flashtestations.tee_signer(), + ctx, + &mut evm, + ) + } else { + self.signed_increment_flashblocks_tx(ctx, &mut evm) + }; - let da_size = op_alloy_flz::tx_estimated_size_fjord_bytes( - signed_tx.encoded_2718().as_slice(), - ); - Some(BuilderTransactionCtx { - gas_used, - da_size, - signed_tx, - is_top_of_block: true, // number tx at top of flashblock - }) - } - Err(e) => { - warn!(target: "builder_tx", error = ?e, "Flashblocks number contract tx simulation failed, defaulting to fallback builder tx"); - self.base_builder_tx - .simulate_builder_tx(ctx, &mut *db)? - .map(|tx| tx.set_top_of_block()) - } - }; + let tx = match flashblocks_num_tx { + Ok(tx) => Some(tx), + Err(e) => { + warn!(target: "builder_tx", error = ?e, "flashblocks number contract tx simulation failed, defaulting to fallback builder tx"); + self.base_builder_tx + .simulate_builder_tx(ctx, &mut *db)? + .map(|tx| tx.set_top_of_block()) + } + }; - builder_txs.extend(tx); - } + builder_txs.extend(tx); } if ctx.is_last_flashblock() { diff --git a/crates/op-rbuilder/src/builders/flashblocks/config.rs b/crates/op-rbuilder/src/builders/flashblocks/config.rs index a3345edb..a47cc046 100644 --- a/crates/op-rbuilder/src/builders/flashblocks/config.rs +++ b/crates/op-rbuilder/src/builders/flashblocks/config.rs @@ -39,6 +39,9 @@ pub struct FlashblocksConfig { /// If set a builder tx will be added to the start of every flashblock instead of the regular builder tx. pub flashblocks_number_contract_address: Option
, + /// whether to use permit signatures for the contract calls + pub flashblocks_number_contract_use_permit: bool, + /// Whether to enable the p2p node for flashblocks pub p2p_enabled: bool, @@ -64,6 +67,7 @@ impl Default for FlashblocksConfig { fixed: false, calculate_state_root: true, flashblocks_number_contract_address: None, + flashblocks_number_contract_use_permit: false, p2p_enabled: false, p2p_port: 9009, p2p_private_key_file: None, @@ -93,6 +97,9 @@ impl TryFrom for FlashblocksConfig { let flashblocks_number_contract_address = args.flashblocks.flashblocks_number_contract_address; + let flashblocks_number_contract_use_permit = + args.flashblocks.flashblocks_number_contract_use_permit; + Ok(Self { ws_addr, interval, @@ -100,6 +107,7 @@ impl TryFrom for FlashblocksConfig { fixed, calculate_state_root, flashblocks_number_contract_address, + flashblocks_number_contract_use_permit, p2p_enabled: args.flashblocks.p2p.p2p_enabled, p2p_port: args.flashblocks.p2p.p2p_port, p2p_private_key_file: args.flashblocks.p2p.p2p_private_key_file, diff --git a/crates/op-rbuilder/src/builders/flashblocks/service.rs b/crates/op-rbuilder/src/builders/flashblocks/service.rs index e11fa2f2..bf3e1c2f 100644 --- a/crates/op-rbuilder/src/builders/flashblocks/service.rs +++ b/crates/op-rbuilder/src/builders/flashblocks/service.rs @@ -188,15 +188,18 @@ where None }; - if let Some(flashblocks_number_contract_address) = - self.0.specific.flashblocks_number_contract_address + if let Some(builder_signer) = signer + && let Some(flashblocks_number_contract_address) = + self.0.specific.flashblocks_number_contract_address { + let use_permit = self.0.specific.flashblocks_number_contract_use_permit; self.spawn_payload_builder_service( ctx, pool, FlashblocksNumberBuilderTx::new( - signer, + builder_signer, flashblocks_number_contract_address, + use_permit, flashtestations_builder_tx, ), ) diff --git a/crates/op-rbuilder/src/flashtestations/args.rs b/crates/op-rbuilder/src/flashtestations/args.rs index 7856bb01..44d1b126 100644 --- a/crates/op-rbuilder/src/flashtestations/args.rs +++ b/crates/op-rbuilder/src/flashtestations/args.rs @@ -83,6 +83,14 @@ pub struct FlashtestationsArgs { default_value = "1" )] pub builder_proof_version: u8, + + /// Use permit for the flashtestation builder tx + #[arg( + long = "flashtestations.use-permit", + env = "FLASHTESTATIONS_USE_PERMIT", + default_value = "false" + )] + pub flashtestations_use_permit: bool, } impl Default for FlashtestationsArgs { diff --git a/crates/op-rbuilder/src/flashtestations/builder_tx.rs b/crates/op-rbuilder/src/flashtestations/builder_tx.rs index 005dcab5..a031f57b 100644 --- a/crates/op-rbuilder/src/flashtestations/builder_tx.rs +++ b/crates/op-rbuilder/src/flashtestations/builder_tx.rs @@ -89,6 +89,10 @@ where } } + pub fn tee_signer(&self) -> &Signer { + &self.tee_service_signer + } + /// Computes the block content hash according to the formula: /// keccak256(abi.encode(parentHash, blockNumber, timestamp, transactionHashes)) /// https://github.com/flashbots/rollup-boost/blob/main/specs/flashtestations.md#block-building-process @@ -136,6 +140,7 @@ where .evm_with_env(&mut simulation_state, ctx.evm_env.clone()); evm.modify_cfg(|cfg| { cfg.disable_balance_check = true; + cfg.disable_nonce_check = true; }); let calldata = IFlashtestationRegistry::getRegistrationStatusCall { teeAddress: self.tee_service_signer.address, @@ -336,7 +341,7 @@ where .gas_limit(ctx.block_gas_limit()) .max_fee_per_gas(ctx.base_fee().into()) .to(contract_address) - .from(self.tee_service_signer.address) // use tee key as signer for simulations + .from(self.builder_signer.address) .nonce(get_nonce(evm.db(), self.tee_service_signer.address)?) .input(TransactionInput::new(calldata.abi_encode().into())); if contract_address == self.registry_address { diff --git a/crates/op-rbuilder/src/tests/flashblocks.rs b/crates/op-rbuilder/src/tests/flashblocks.rs index a623aaff..cd92da9f 100644 --- a/crates/op-rbuilder/src/tests/flashblocks.rs +++ b/crates/op-rbuilder/src/tests/flashblocks.rs @@ -526,7 +526,7 @@ async fn test_flashblocks_number_contract_builder_tx(rbuilder: LocalInstance) -> let init_tx = driver .create_transaction() .init_flashblock_number_contract(true) - .with_to(contract_address) + .with_to(FLASHBLOCKS_NUMBER_ADDRESS) .with_bundle(BundleOpts::default()) .send() .await?; diff --git a/crates/op-rbuilder/src/tests/flashtestations.rs b/crates/op-rbuilder/src/tests/flashtestations.rs index c0cc0250..8ca8795f 100644 --- a/crates/op-rbuilder/src/tests/flashtestations.rs +++ b/crates/op-rbuilder/src/tests/flashtestations.rs @@ -97,7 +97,6 @@ async fn test_flashtestations_unauthorized_workload(rbuilder: LocalInstance) -> // check that only the regular builder tx is in the block let (tx_hash, block) = driver.build_new_block_with_valid_transaction().await?; let txs = block.transactions.into_transactions_vec(); - if_flashblocks!( assert_eq!(txs.len(), 4, "Expected 4 transactions in block"); // deposit + valid tx + 2 builder tx // Check builder tx @@ -312,7 +311,6 @@ async fn test_flashtestations_permit_with_flashblocks_number_contract( .send() .await?; let block = driver.build_new_block_with_current_timestamp(None).await?; - // check the builder tx, funding tx and registration tx is in the block let num_txs = block.transactions.len(); let txs = block.transactions.into_transactions_vec(); // // 1 deposit tx, 1 regular builder tx, 4 flashblocks number tx, 1 user tx, 1 block proof tx @@ -358,6 +356,121 @@ async fn test_flashtestations_permit_with_flashblocks_number_contract( Ok(()) } +#[rb_test(flashblocks, args = OpRbuilderArgs { + chain_block_time: 1000, + enable_revert_protection: true, + flashblocks: FlashblocksArgs { + flashblocks_number_contract_address: Some(FLASHBLOCKS_NUMBER_ADDRESS), + flashblocks_number_contract_use_permit: true, + ..Default::default() + }, + flashtestations: FlashtestationsArgs { + flashtestations_enabled: true, + registry_address: Some(FLASHTESTATION_REGISTRY_ADDRESS), + builder_policy_address: Some(BLOCK_BUILDER_POLICY_ADDRESS), + debug: true, + flashtestations_use_permit: true, + enable_block_proofs: true, + ..Default::default() + }, + ..Default::default() +})] +async fn test_flashtestations_permit_with_flashblocks_number_permit( + rbuilder: LocalInstance, +) -> eyre::Result<()> { + let driver = rbuilder.driver().await?; + let provider = rbuilder.provider().await?; + setup_flashblock_number_contract(&driver, &provider, false).await?; + setup_flashtestation_contracts(&driver, &provider, true, true).await?; + // Verify flashblock number is not incremented and builder address is not authorized + let contract = FlashblocksNumber::new(FLASHBLOCKS_NUMBER_ADDRESS, provider.clone()); + let current_number = contract.getFlashblockNumber().call().await?; + assert!( + current_number.is_zero(), // contract deployments incremented the number but we built at least 1 full block + "Flashblock number should not be incremented" + ); + let is_authorized = contract.isBuilder(builder_signer().address).call().await?; + assert!(!is_authorized, "builder should not be authorized"); + + // add tee signer address to authorized builders + let add_builder_tx = driver + .create_transaction() + .add_authorized_builder(TEE_DEBUG_ADDRESS) + .with_to(FLASHBLOCKS_NUMBER_ADDRESS) + .with_bundle(BundleOpts::default().with_flashblock_number_min(4)) + .send() + .await?; + let block = driver.build_new_block_with_current_timestamp(None).await?; + provider + .get_transaction_receipt(*add_builder_tx.tx_hash()) + .await? + .expect("add builder tx not mined"); + let num_txs = block.transactions.len(); + let txs = block.transactions.into_transactions_vec(); + // 1 deposit tx, 5 regular builder tx, 1 add builder tx, 1 block proof tx + assert_eq!(num_txs, 8, "Expected 8 transactions in block"); + // Check no transactions to the flashblocks number contract as tee signer is not authorized + for i in 1..6 { + assert_eq!( + txs[i].to(), + Some(Address::ZERO), + "builder tx should send to flashblocks number contract at index {}", + i + ); + } + // add builder tx + assert_eq!( + txs[6].tx_hash(), + *add_builder_tx.tx_hash(), + "add builder tx should be in correct position in block" + ); + assert_eq!( + txs[7].to(), + Some(BLOCK_BUILDER_POLICY_ADDRESS), + "builder tx should send verify block builder proof" + ); + + let tx = driver + .create_transaction() + .random_valid_transfer() + .with_bundle(BundleOpts::default().with_flashblock_number_min(4)) + .send() + .await?; + let block = driver.build_new_block_with_current_timestamp(None).await?; + let txs = block.transactions.into_transactions_vec(); + // 1 deposit tx, 1 regular builder tx, 4 flashblocks builder tx, 1 user tx, 1 block proof tx + assert_eq!(txs.len(), 8, "Expected 8 transactions in block"); + // flashblocks number contract + for i in 2..6 { + assert_eq!( + txs[i].to(), + Some(FLASHBLOCKS_NUMBER_ADDRESS), + "builder tx should send to flashblocks number contract at index {}", + i + ); + } + // user tx + assert_eq!( + txs[6].tx_hash(), + *tx.tx_hash(), + "user tx should be in correct position in block" + ); + // check that the tee signer did not send any transactions + let balance = provider.get_balance(TEE_DEBUG_ADDRESS).await?; + assert!(balance.is_zero()); + let nonce = provider.get_transaction_count(TEE_DEBUG_ADDRESS).await?; + assert_eq!(nonce, 0); + // Verify flashblock number incremented correctly + let contract = FlashblocksNumber::new(FLASHBLOCKS_NUMBER_ADDRESS, provider.clone()); + let current_number = contract.getFlashblockNumber().call().await?; + assert_eq!( + current_number, + U256::from(4), + "Flashblock number not incremented correctly" + ); + Ok(()) +} + async fn setup_flashtestation_contracts( driver: &ChainDriver, provider: &RootProvider, diff --git a/crates/op-rbuilder/src/tests/framework/instance.rs b/crates/op-rbuilder/src/tests/framework/instance.rs index ccfadaf0..d698bf45 100644 --- a/crates/op-rbuilder/src/tests/framework/instance.rs +++ b/crates/op-rbuilder/src/tests/framework/instance.rs @@ -52,7 +52,6 @@ use std::{ use tokio::{net::TcpListener, sync::oneshot, task::JoinHandle}; use tokio_tungstenite::{connect_async, tungstenite::Message}; use tokio_util::sync::CancellationToken; -use tracing::warn; /// Represents a type that emulates a local in-process instance of the OP builder node. /// This node uses IPC as the communication channel for the RPC server Engine API. @@ -410,7 +409,6 @@ impl FlashblocksListener { } Some(Ok(Message::Text(text))) = read.next() => { let fb = serde_json::from_str(&text).unwrap(); - warn!("GOT FB: {fb:#?}"); flashblocks_clone.lock().push(fb); } } diff --git a/crates/op-rbuilder/src/tests/framework/utils.rs b/crates/op-rbuilder/src/tests/framework/utils.rs index 35a5f2a5..99772de1 100644 --- a/crates/op-rbuilder/src/tests/framework/utils.rs +++ b/crates/op-rbuilder/src/tests/framework/utils.rs @@ -33,6 +33,7 @@ pub trait TransactionBuilderExt { // flashblocks number methods fn deploy_flashblock_number_contract(self) -> Self; fn init_flashblock_number_contract(self, register_builder: bool) -> Self; + fn add_authorized_builder(self, builder: Address) -> Self; // flashtestations methods fn deploy_flashtestation_registry_contract(self) -> Self; fn init_flashtestation_registry_contract(self, dcap_address: Address) -> Self; @@ -85,6 +86,13 @@ impl TransactionBuilderExt for TransactionBuilder { .with_signer(flashblocks_number_signer()) } + fn add_authorized_builder(self, builder: Address) -> Self { + let calldata = FlashblocksNumber::addBuilderCall { builder }.abi_encode(); + + self.with_input(calldata.into()) + .with_signer(flashblocks_number_signer()) + } + fn deploy_flashtestation_registry_contract(self) -> Self { self.with_create() .with_input(FlashtestationRegistry::BYTECODE.clone())