@@ -194,6 +194,159 @@ impl EngineClient for RethEngineClient {
194194 }
195195}
196196
197+ #[ cfg( feature = "bad-blocks" ) ]
198+ #[ derive( Clone ) ]
199+ pub struct BadBlockEngineClient {
200+ engine_ipc_path : String ,
201+ provider : RootProvider ,
202+ /// How often a bad block should happen
203+ bad_block_timing : u64 ,
204+ }
205+
206+ #[ cfg( feature = "bad-blocks" ) ]
207+ impl BadBlockEngineClient {
208+ pub async fn new ( engine_ipc_path : String , bad_block_timing : u64 ) -> Self {
209+ let ipc = IpcConnect :: new ( engine_ipc_path. clone ( ) ) ;
210+ let provider = ProviderBuilder :: default ( ) . connect_ipc ( ipc) . await . unwrap ( ) ;
211+ Self {
212+ provider,
213+ engine_ipc_path,
214+ bad_block_timing,
215+ }
216+ }
217+
218+ pub async fn wait_until_reconnect_available ( & mut self ) {
219+ loop {
220+ let ipc = IpcConnect :: new ( self . engine_ipc_path . clone ( ) ) ;
221+
222+ match ProviderBuilder :: default ( ) . connect_ipc ( ipc) . await {
223+ Ok ( provider) => {
224+ self . provider = provider;
225+ break ;
226+ }
227+ Err ( e) => {
228+ error ! ( "Failed to connect to IPC, retrying: {}" , e) ;
229+ tokio:: time:: sleep ( tokio:: time:: Duration :: from_millis ( 100 ) ) . await ;
230+ }
231+ }
232+ }
233+ }
234+ }
235+
236+ #[ cfg( feature = "bad-blocks" ) ]
237+ impl EngineClient for BadBlockEngineClient {
238+ async fn start_building_block (
239+ & mut self ,
240+ fork_choice_state : ForkchoiceState ,
241+ timestamp : u64 ,
242+ withdrawals : Vec < Withdrawal > ,
243+ suggested_fee_recipient : Address ,
244+ parent_beacon_block_root : Option < FixedBytes < 32 > > ,
245+ #[ cfg( feature = "bench" ) ] _height : u64 ,
246+ ) -> Option < PayloadId > {
247+ let payload_attributes = PayloadAttributes {
248+ timestamp,
249+ prev_randao : [ 0 ; 32 ] . into ( ) ,
250+ // todo(dalton): this should be the validators public key
251+ suggested_fee_recipient,
252+ withdrawals : Some ( withdrawals) ,
253+ // todo(dalton): we should make this something that we can associate with the simplex height
254+ parent_beacon_block_root,
255+ } ;
256+
257+ let res = match self
258+ . provider
259+ . fork_choice_updated_v3 ( fork_choice_state, Some ( payload_attributes. clone ( ) ) )
260+ . await
261+ {
262+ Ok ( res) => res,
263+ Err ( e) if e. is_transport_error ( ) => {
264+ self . wait_until_reconnect_available ( ) . await ;
265+ self . provider
266+ . fork_choice_updated_v3 ( fork_choice_state, Some ( payload_attributes) )
267+ . await
268+ . expect ( "Failed to update fork choice after reconnect" )
269+ }
270+ Err ( _) => panic ! ( "Unable to get a response" ) ,
271+ } ;
272+
273+ if res. is_invalid ( ) {
274+ error ! ( "invalid returned for forkchoice state {fork_choice_state:?}: {res:?}" ) ;
275+ }
276+ if res. is_syncing ( ) {
277+ warn ! ( "syncing returned for forkchoice state {fork_choice_state:?}: {res:?}" ) ;
278+ }
279+
280+ res. payload_id
281+ }
282+
283+ async fn get_payload ( & mut self , payload_id : PayloadId ) -> ExecutionPayloadEnvelopeV4 {
284+ match self . provider . get_payload_v4 ( payload_id) . await {
285+ Ok ( res) => res,
286+ Err ( e) if e. is_transport_error ( ) => {
287+ self . wait_until_reconnect_available ( ) . await ;
288+ self . provider
289+ . get_payload_v4 ( payload_id)
290+ . await
291+ . expect ( "Failed to get payload after reconnect" )
292+ }
293+ Err ( _) => panic ! ( "Unable to get a response" ) ,
294+ }
295+ }
296+
297+ async fn check_payload ( & mut self , block : & Block ) -> PayloadStatus {
298+ let parent_beacon_block_root = if block. height ( ) . is_multiple_of ( self . bad_block_timing ) {
299+ [ 1 ; 32 ] . into ( )
300+ } else {
301+ block. parent ( ) . 0 . into ( )
302+ } ;
303+
304+ match self
305+ . provider
306+ . new_payload_v4 (
307+ block. payload . clone ( ) ,
308+ Vec :: new ( ) ,
309+ parent_beacon_block_root,
310+ block. execution_requests . clone ( ) ,
311+ )
312+ . await
313+ {
314+ Ok ( res) => res,
315+ Err ( e) if e. is_transport_error ( ) => {
316+ self . wait_until_reconnect_available ( ) . await ;
317+ self . provider
318+ . new_payload_v4 (
319+ block. payload . clone ( ) ,
320+ Vec :: new ( ) ,
321+ [ 1 ; 32 ] . into ( ) ,
322+ block. execution_requests . clone ( ) ,
323+ )
324+ . await
325+ . expect ( "Failed to check payload after reconnect" )
326+ }
327+ Err ( _) => panic ! ( "Unable to get a response" ) ,
328+ }
329+ }
330+
331+ async fn commit_hash ( & mut self , fork_choice_state : ForkchoiceState ) {
332+ let _ = match self
333+ . provider
334+ . fork_choice_updated_v3 ( fork_choice_state, None )
335+ . await
336+ {
337+ Ok ( res) => res,
338+ Err ( e) if e. is_transport_error ( ) => {
339+ self . wait_until_reconnect_available ( ) . await ;
340+ self . provider
341+ . fork_choice_updated_v3 ( fork_choice_state, None )
342+ . await
343+ . expect ( "Failed to get payload after reconnect" )
344+ }
345+ Err ( _) => panic ! ( "Unable to get a response" ) ,
346+ } ;
347+ }
348+ }
349+
197350#[ cfg( feature = "bench" ) ]
198351pub mod benchmarking {
199352 use crate :: engine_client:: EngineClient ;
0 commit comments