@@ -36,10 +36,12 @@ use reth_revm::{State, context::Block};
3636use reth_transaction_pool:: { BestTransactionsAttributes , PoolTransaction } ;
3737use revm:: { DatabaseCommit , context:: result:: ResultAndState , interpreter:: as_u64_saturated} ;
3838use std:: { sync:: Arc , time:: Instant } ;
39+ use tips_audit:: BundleEvent ;
3940use tokio_util:: sync:: CancellationToken ;
40- use tracing:: { debug, info, trace} ;
41+ use tracing:: { debug, info, trace, warn } ;
4142
4243use crate :: {
44+ bundles:: AuditSender ,
4345 gas_limiter:: AddressGasLimiter ,
4446 metrics:: OpRBuilderMetrics ,
4547 primitives:: reth:: { ExecutionInfo , TxnExecutionResult } ,
@@ -82,6 +84,8 @@ pub struct OpPayloadBuilderCtx<ExtraCtx: Debug + Default = ()> {
8284 pub resource_metering : ResourceMetering ,
8385 /// Backrun bundle store for storing backrun transactions
8486 pub backrun_bundle_store : crate :: bundles:: BackrunBundleStore ,
87+ /// Audit event channel for backrun bundle lifecycle tracking
88+ pub audit_tx : Option < AuditSender > ,
8589}
8690
8791impl < ExtraCtx : Debug + Default > OpPayloadBuilderCtx < ExtraCtx > {
@@ -93,6 +97,19 @@ impl<ExtraCtx: Debug + Default> OpPayloadBuilderCtx<ExtraCtx> {
9397 Self { extra_ctx, ..self }
9498 }
9599
100+ /// Send an audit event if the audit channel is configured
101+ fn send_audit_event ( & self , event : BundleEvent ) {
102+ if let Some ( ref audit_tx) = self . audit_tx {
103+ if let Err ( e) = audit_tx. send ( event) {
104+ warn ! (
105+ target: "payload_builder" ,
106+ error = %e,
107+ "Failed to send audit event"
108+ ) ;
109+ }
110+ }
111+ }
112+
96113 /// Returns the parent block the payload will be build on.
97114 pub fn parent ( & self ) -> & SealedHeader {
98115 & self . config . parent_header
@@ -447,6 +464,17 @@ impl<ExtraCtx: Debug + Default> OpPayloadBuilderCtx<ExtraCtx> {
447464
448465 num_txs_considered += 1 ;
449466
467+ // Look up bundle_id for this tx (registered via base_txBundleId RPC)
468+ let bundle_id = self . backrun_bundle_store . get_tx_bundle_id ( & tx_hash) ;
469+
470+ // Emit StartExecuting audit event - tx is about to be executed
471+ self . send_audit_event ( BundleEvent :: StartExecuting {
472+ bundle_id,
473+ tx_hash,
474+ block_number : self . block_number ( ) ,
475+ timestamp_ms : chrono:: Utc :: now ( ) . timestamp_millis ( ) ,
476+ } ) ;
477+
450478 let _resource_usage = self . resource_metering . get ( & tx_hash) ;
451479
452480 // TODO: ideally we should get this from the txpool stream
@@ -607,11 +635,89 @@ impl<ExtraCtx: Debug + Default> OpPayloadBuilderCtx<ExtraCtx> {
607635
608636 info ! ( message = "Executed transaction" , tx_hash = ?tx_hash) ;
609637
638+ // Emit Executed audit event - tx successfully executed and committed
639+ self . send_audit_event ( BundleEvent :: Executed {
640+ bundle_id,
641+ tx_hash,
642+ block_number : self . block_number ( ) ,
643+ gas_used,
644+ timestamp_ms : chrono:: Utc :: now ( ) . timestamp_millis ( ) ,
645+ } ) ;
646+
610647 // Execute backrun bundles for this transaction if it succeeded
611648 if is_success && let Some ( backrun_bundles) = self . backrun_bundle_store . get ( & tx_hash) {
612- info ! ( target : "backrun_bundles ", target_tx = ?tx_hash, bundle_count = backrun_bundles. len( ) , "Found backrun bundles for transaction" ) ;
649+ info ! ( message = "Found backrun bundles for transaction ", tx_hash = ?tx_hash, bundle_count = backrun_bundles. len( ) ) ;
613650 self . metrics . backrun_target_txs_found_total . increment ( 1 ) ;
614- // TODO: Execute backrun bundles
651+
652+ for stored_bundle in backrun_bundles {
653+ let bundle_id = stored_bundle. bundle_id ;
654+ for backrun_tx in stored_bundle. backrun_txs {
655+ let ResultAndState { result, state } = match evm. transact ( & backrun_tx) {
656+ Ok ( res) => res,
657+ Err ( err) => {
658+ return Err ( PayloadBuilderError :: evm ( err) ) ;
659+ }
660+ } ;
661+
662+ let backrun_gas_used = result. gas_used ( ) ;
663+ let is_backrun_success = result. is_success ( ) ;
664+
665+ if !is_backrun_success {
666+ info ! ( message = "Backrun transaction reverted" , tx_hash = ?backrun_tx. tx_hash( ) , bundle_id = %bundle_id) ;
667+
668+ // Emit BackrunBundleExecuted audit event for reverted tx
669+ self . send_audit_event ( BundleEvent :: BackrunBundleExecuted {
670+ bundle_id,
671+ target_tx_hash : tx_hash,
672+ backrun_tx_hash : backrun_tx. tx_hash ( ) ,
673+ block_number : self . block_number ( ) ,
674+ gas_used : backrun_gas_used,
675+ success : false ,
676+ timestamp_ms : chrono:: Utc :: now ( ) . timestamp_millis ( ) ,
677+ } ) ;
678+
679+ continue ;
680+ }
681+
682+ info ! ( message = "Backrun transaction succeeded" , tx_hash = ?backrun_tx. tx_hash( ) , bundle_id = %bundle_id) ;
683+
684+ info. cumulative_gas_used += backrun_gas_used;
685+ info. cumulative_da_bytes_used += backrun_tx. encoded_2718 ( ) . len ( ) as u64 ;
686+
687+ let ctx = ReceiptBuilderCtx {
688+ tx : backrun_tx. inner ( ) ,
689+ evm : & evm,
690+ result,
691+ state : & state,
692+ cumulative_gas_used : info. cumulative_gas_used ,
693+ } ;
694+ info. receipts . push ( self . build_receipt ( ctx, None ) ) ;
695+
696+ // commit changes
697+ evm. db_mut ( ) . commit ( state) ;
698+
699+ // Emit BackrunBundleExecuted audit event for successful tx
700+ self . send_audit_event ( BundleEvent :: BackrunBundleExecuted {
701+ bundle_id,
702+ target_tx_hash : tx_hash,
703+ backrun_tx_hash : backrun_tx. tx_hash ( ) ,
704+ block_number : self . block_number ( ) ,
705+ gas_used : backrun_gas_used,
706+ success : true ,
707+ timestamp_ms : chrono:: Utc :: now ( ) . timestamp_millis ( ) ,
708+ } ) ;
709+
710+ // update add to total fees
711+ let miner_fee = backrun_tx
712+ . effective_tip_per_gas ( base_fee)
713+ . expect ( "fee is always valid; execution succeeded" ) ;
714+ info. total_fees += U256 :: from ( miner_fee) * U256 :: from ( backrun_gas_used) ;
715+
716+ // append sender and transaction to the respective lists
717+ info. executed_senders . push ( backrun_tx. signer ( ) ) ;
718+ info. executed_transactions . push ( backrun_tx. into_inner ( ) ) ;
719+ }
720+ }
615721 }
616722 }
617723
0 commit comments