Skip to content

Commit fbd8fb9

Browse files
authored
fix: nodes would still try and build ontop a bad eth block (#125)
1 parent 91ccf66 commit fbd8fb9

5 files changed

Lines changed: 166 additions & 4 deletions

File tree

application/src/actor.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ impl<
389389
.await
390390
.expect("Finalizer dropped");
391391

392-
let Some(mut aux_data) = maybe_aux_data else {
392+
let Some(aux_data) = maybe_aux_data else {
393393
debug!(
394394
"Aborting block proposal for epoch {} and height {} because of an outdated aux data request",
395395
round.epoch().get(),
@@ -440,7 +440,7 @@ impl<
440440
#[cfg(feature = "prom")]
441441
let start_building_start = std::time::Instant::now();
442442

443-
aux_data.forkchoice.head_block_hash = parent_block.eth_block_hash().into();
443+
// aux_data.forkchoice.head_block_hash = parent_block.eth_block_hash().into();
444444

445445
// Add pending withdrawals to the block
446446
let withdrawals = pending_withdrawals.into_iter().map(|w| w.inner).collect();

node/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,4 @@ tokio-console = ["console-subscriber"]
143143
jemalloc = ["dep:tikv-jemalloc-ctl"]
144144
bench = ["summit-application/bench", "summit-types/bench"]
145145
e2e = ["summit-types/e2e"]
146+
bad-blocks = ["summit-types/bad-blocks"]

node/src/args.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ use std::{
3030
#[cfg(feature = "bench")]
3131
use summit_types::engine_client::benchmarking::EthereumHistoricalEngineClient;
3232

33+
#[cfg(feature = "bad-blocks")]
34+
use summit_types::engine_client::BadBlockEngineClient;
35+
3336
use crate::config::MAILBOX_SIZE;
3437
use summit_types::FinalizedHeader;
3538
#[cfg(not(feature = "bench"))]
@@ -521,7 +524,11 @@ pub fn run_node_local(
521524
.await
522525
};
523526

524-
#[cfg(not(feature = "bench"))]
527+
#[cfg(feature = "bad-blocks")]
528+
let engine_client =
529+
BadBlockEngineClient::new(engine_ipc_path.to_string_lossy().to_string(), 4).await; // make every 4th block a bad eth payload
530+
531+
#[cfg(all(not(feature = "bench"), not(feature = "bad-blocks")))]
525532
let engine_client =
526533
RethEngineClient::new(engine_ipc_path.to_string_lossy().to_string()).await;
527534

types/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,5 @@ libc = { version = "0.2.174", optional = true}
4242

4343
[features]
4444
bench = ["serde_json"]
45-
e2e = ["libc", "alloy-genesis", "url"]
45+
e2e = ["libc", "alloy-genesis", "url"]
46+
bad-blocks = []

types/src/engine_client.rs

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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")]
198351
pub mod benchmarking {
199352
use crate::engine_client::EngineClient;

0 commit comments

Comments
 (0)