@@ -11,7 +11,9 @@ use op_alloy_network::Optimism;
1111use reth_rpc_eth_types:: EthApiError ;
1212use std:: time:: { SystemTime , UNIX_EPOCH } ;
1313use tips_audit:: { BundleEvent , BundleEventPublisher } ;
14- use tips_core:: { Bundle , BundleHash , BundleWithMetadata , CancelBundle } ;
14+ use tips_core:: {
15+ BLOCK_TIME , Bundle , BundleHash , BundleWithMetadata , CancelBundle , MeterBundleResponse ,
16+ } ;
1517use tracing:: { info, warn} ;
1618
1719use crate :: queue:: QueuePublisher ;
6567 Audit : BundleEventPublisher + Sync + Send + ' static ,
6668{
6769 async fn send_bundle ( & self , bundle : Bundle ) -> RpcResult < BundleHash > {
68- let bundle_with_metadata = self . validate_bundle ( bundle) . await ?;
70+ self . validate_bundle ( & bundle) . await ?;
71+ let meter_bundle_response = self . meter_bundle ( & bundle) . await ?;
72+ let bundle_with_metadata = BundleWithMetadata :: load ( bundle, meter_bundle_response)
73+ . map_err ( |e| EthApiError :: InvalidParams ( e. to_string ( ) ) . into_rpc_err ( ) ) ?;
6974
7075 let bundle_hash = bundle_with_metadata. bundle_hash ( ) ;
7176 if let Err ( e) = self
@@ -117,8 +122,9 @@ where
117122 reverting_tx_hashes : vec ! [ transaction. tx_hash( ) ] ,
118123 ..Default :: default ( )
119124 } ;
125+ let meter_bundle_response = self . meter_bundle ( & bundle) . await ?;
120126
121- let bundle_with_metadata = BundleWithMetadata :: load ( bundle)
127+ let bundle_with_metadata = BundleWithMetadata :: load ( bundle, meter_bundle_response )
122128 . map_err ( |e| EthApiError :: InvalidParams ( e. to_string ( ) ) . into_rpc_err ( ) ) ?;
123129 let bundle_hash = bundle_with_metadata. bundle_hash ( ) ;
124130
@@ -191,25 +197,44 @@ where
191197 Ok ( transaction)
192198 }
193199
194- async fn validate_bundle ( & self , bundle : Bundle ) -> RpcResult < BundleWithMetadata > {
200+ async fn validate_bundle ( & self , bundle : & Bundle ) -> RpcResult < ( ) > {
195201 if bundle. txs . is_empty ( ) {
196202 return Err (
197203 EthApiError :: InvalidParams ( "Bundle cannot have empty transactions" . into ( ) )
198204 . into_rpc_err ( ) ,
199205 ) ;
200206 }
201207
202- let bundle_with_metadata = BundleWithMetadata :: load ( bundle. clone ( ) )
203- . map_err ( |e| EthApiError :: InvalidParams ( e. to_string ( ) ) . into_rpc_err ( ) ) ?;
204- let tx_hashes = bundle_with_metadata. txn_hashes ( ) ;
205-
206208 let mut total_gas = 0u64 ;
209+ let mut tx_hashes = Vec :: new ( ) ;
207210 for tx_data in & bundle. txs {
208211 let transaction = self . validate_tx ( tx_data) . await ?;
209212 total_gas = total_gas. saturating_add ( transaction. gas_limit ( ) ) ;
213+ tx_hashes. push ( transaction. tx_hash ( ) ) ;
210214 }
211- validate_bundle ( & bundle, total_gas, tx_hashes) ?;
215+ validate_bundle ( bundle, total_gas, tx_hashes) ?;
212216
213- Ok ( bundle_with_metadata)
217+ Ok ( ( ) )
218+ }
219+
220+ /// `meter_bundle` is used to determine how long a bundle will take to execute. A bundle that
221+ /// is within `BLOCK_TIME` will return the `MeterBundleResponse` that can be passed along
222+ /// to the builder.
223+ async fn meter_bundle ( & self , bundle : & Bundle ) -> RpcResult < MeterBundleResponse > {
224+ let res: MeterBundleResponse = self
225+ . provider
226+ . client ( )
227+ . request ( "base_meterBundle" , ( bundle, ) )
228+ . await
229+ . map_err ( |e| EthApiError :: InvalidParams ( e. to_string ( ) ) . into_rpc_err ( ) ) ?;
230+
231+ // we can save some builder payload building computation by not including bundles
232+ // that we know will take longer than the block time to execute
233+ if res. total_execution_time_us > BLOCK_TIME {
234+ return Err (
235+ EthApiError :: InvalidParams ( "Bundle simulation took too long" . into ( ) ) . into_rpc_err ( ) ,
236+ ) ;
237+ }
238+ Ok ( res)
214239 }
215240}
0 commit comments