Skip to content

Commit 1d1adfb

Browse files
fedackingmpaulucci
authored andcommitted
fix(l1): added checks to newpayload and forkchoiceupdated (#2831)
**Motivation** This should fix some sync and inconsistent behaviour problems with the hive engine tests. The problem was happening when a sync process had begun, and a block from that sync process entered the server. Some checks for that scenario have been added. Also made some tests in the CI easier to read and edit, while adding a couple of them. **Description** - Made the CI tests have 1 by 1. - Added some fixed CI tests to "Paris Engine tests" and "Engine withdrawal tests" - Added a check to forkchoiceupdatet for the body to be present before forking. - Added a check to execute_payload for the body of the parent to be present before executing. Fixes some tests in #1285
1 parent 5f0ec41 commit 1d1adfb

File tree

4 files changed

+85
-27
lines changed

4 files changed

+85
-27
lines changed

.github/workflows/pr-main_l1.yaml

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,11 +160,53 @@ jobs:
160160
ethrex_flags: ""
161161
- name: "Paris Engine tests"
162162
simulation: ethereum/engine
163-
test_pattern: "engine-api/RPC|Re-org to Previously Validated Sidechain Payload|Re-Org Back into Canonical Chain, Depth=5|Safe Re-Org|Transaction Re-Org|Inconsistent|Suggested Fee|PrevRandao Opcode Transactions|Fork ID|Unknown SafeBlockHash|Unknown FinalizedBlockHash|Unique Payload ID|Re-Execute Payload|Multiple New Payloads|NewPayload with|Payload Build|Build Payload|Invalid PayloadAttributes|Unknown HeadBlockHash|Valid NewPayload->ForkchoiceUpdated|Invalid NewPayload, ParentHash|Bad Hash on NewPayload|In-Order Consecutive Payload Execution|Re-Org Back to Canonical Chain" # |Invalid P9 -> flaky
163+
test_pattern: "engine-api/RPC|
164+
Bad Hash on NewPayload|
165+
Build Payload|
166+
Fork ID|
167+
In-Order Consecutive Payload Execution|
168+
Inconsistent|
169+
Invalid Missing Ancestor ReOrg|
170+
Invalid NewPayload|
171+
Invalid PayloadAttributes|
172+
Multiple New Payloads|
173+
NewPayload with|
174+
ParentHash equals BlockHash on NewPayload|
175+
Payload Build|
176+
PrevRandao Opcode Transactions|
177+
Re-Execute Payload|
178+
Re-Org Back|
179+
Re-org to Previously Validated Sidechain Payload|
180+
RPC:|
181+
Safe Re-Org|
182+
Suggested Fee|
183+
Transaction Re-Org|
184+
Unique Payload ID|
185+
Unknown|
186+
Valid NewPayload->ForkchoiceUpdated" # |Invalid P9 -> flaky
164187
ethrex_flags: ""
165188
- name: "Engine withdrawal tests"
166189
simulation: ethereum/engine
167-
test_pattern: "engine-withdrawals/engine-withdrawals test loader|GetPayloadV2 Block Value|Sync after 2 blocks - Withdrawals on Genesis|Max Initcode Size|Pre-Merge Fork Number > 0|Empty Withdrawals|Corrupted Block Hash Payload|Withdrawals Fork on Block 2|Withdrawals Fork on Block 3|GetPayloadBodies|Withdrawals Fork on Block 1 - 1 Block Re-Org|Withdrawals Fork on Block 1 - 8 Block Re-Org NewPayload|Withdrawals Fork on Block 8 - 10 Block Re-Org NewPayload|Withdrawals Fork on Canonical Block 8 / Side Block 7 - 10 Block Re-Org [^S]|Withdrawals Fork on Canonical Block 8 / Side Block 9 - 10 Block Re-Org [^S]"
190+
test_pattern: "engine-withdrawals/
191+
Corrupted Block Hash Payload|
192+
Empty Withdrawals|
193+
engine-withdrawals test loader|
194+
GetPayloadBodies|
195+
GetPayloadV2 Block Value|
196+
Max Initcode Size|
197+
Sync after 2 blocks - Withdrawals on Genesis|
198+
Withdraw many accounts|
199+
Withdraw to a single account|
200+
Withdraw to two accounts|
201+
Withdraw zero amount|
202+
Withdraw many accounts|
203+
Withdrawals Fork on Block 1 - 1 Block Re-Org|
204+
Withdrawals Fork on Block 1 - 8 Block Re-Org NewPayload|
205+
Withdrawals Fork on Block 2|
206+
Withdrawals Fork on Block 3|
207+
Withdrawals Fork on Block 8 - 10 Block Re-Org NewPayload|
208+
Withdrawals Fork on Canonical Block 8 / Side Block 7 - 10 Block Re-Org [^S]|
209+
Withdrawals Fork on Canonical Block 8 / Side Block 9 - 10 Block Re-Org [^S]"
168210
ethrex_flags: ""
169211
- name: "Sync full"
170212
simulation: ethereum/sync

crates/blockchain/blockchain.rs

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,21 @@ impl Blockchain {
7676
block: &Block,
7777
) -> Result<(BlockExecutionResult, Vec<AccountUpdate>), ChainError> {
7878
// Validate if it can be the new head and find the parent
79-
let Ok(parent_header) = find_parent_header(&block.header, &self.storage) else {
80-
// If the parent is not present, we store it as pending.
81-
self.storage.add_pending_block(block.clone()).await?;
82-
return Err(ChainError::ParentNotFound);
79+
// Feda (#2831): We search for the entire block because during full/batch sync
80+
// we can have the header without the body indicating it's still syncing.
81+
let parent = self
82+
.storage
83+
.get_block_by_hash(block.header.parent_hash)
84+
.await?;
85+
let parent_header = match parent {
86+
Some(parent_block) => parent_block.header,
87+
None => {
88+
// If the parent is not present, we store it as pending.
89+
self.storage.add_pending_block(block.clone()).await?;
90+
return Err(ChainError::ParentNotFound);
91+
}
8392
};
93+
8494
let chain_config = self.storage.get_chain_config()?;
8595

8696
// Validate the block pre-execution
@@ -231,16 +241,18 @@ impl Blockchain {
231241
}
232242
// for the first block, we need to query the store
233243
let parent_header = if i == 0 {
234-
let Ok(parent_header) = find_parent_header(&block.header, &self.storage) else {
235-
return Err((
236-
ChainError::ParentNotFound,
237-
Some(BatchBlockProcessingFailure {
238-
failed_block_hash: block.hash(),
239-
last_valid_hash,
240-
}),
241-
));
242-
};
243-
parent_header
244+
match find_parent_header(&block.header, &self.storage) {
245+
Ok(parent_header) => parent_header,
246+
Err(error) => {
247+
return Err((
248+
error,
249+
Some(BatchBlockProcessingFailure {
250+
failed_block_hash: block.hash(),
251+
last_valid_hash,
252+
}),
253+
))
254+
}
255+
}
244256
} else {
245257
// for the subsequent ones, the parent is the previous block
246258
blocks[i - 1].header.clone()
@@ -557,8 +569,8 @@ pub async fn latest_canonical_block_hash(storage: &Store) -> Result<H256, ChainE
557569
)))
558570
}
559571

560-
/// Validates if the provided block could be the new head of the chain, and returns the
561-
/// parent_header in that case. If not found, the new block is saved as pending.
572+
/// Searchs the header of the parent block header. If the parent header is missing,
573+
/// Returns a ChainError::ParentNotFound. If the storage has an error it propagates it
562574
pub fn find_parent_header(
563575
block_header: &BlockHeader,
564576
storage: &Store,

crates/blockchain/fork_choice.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,23 @@ pub async fn apply_fork_choice(
4040
None
4141
};
4242

43-
let head_res = store.get_block_header_by_hash(head_hash)?;
43+
// Feda (#2831): We search for the entire block because during full/batch sync
44+
// we can have the header without the body indicating it's still syncing.
45+
let head_block_res = store.get_block_by_hash(head_hash).await?;
46+
47+
let Some(head_block) = head_block_res else {
48+
return Err(InvalidForkChoice::Syncing);
49+
};
4450

4551
if !safe_hash.is_zero() {
46-
check_order(&safe_res, &head_res)?;
52+
check_order(safe_res.as_ref(), Some(&head_block.header))?;
4753
}
4854

4955
if !finalized_hash.is_zero() && !safe_hash.is_zero() {
50-
check_order(&finalized_res, &safe_res)?;
56+
check_order(finalized_res.as_ref(), safe_res.as_ref())?;
5157
}
5258

53-
let Some(head) = head_res else {
54-
return Err(InvalidForkChoice::Syncing);
55-
};
59+
let head = head_block.header;
5660

5761
let latest = store.get_latest_block_number().await?;
5862

@@ -130,8 +134,8 @@ pub async fn apply_fork_choice(
130134

131135
// Checks that block 1 is prior to block 2 and that if the second is present, the first one is too.
132136
fn check_order(
133-
block_1: &Option<BlockHeader>,
134-
block_2: &Option<BlockHeader>,
137+
block_1: Option<&BlockHeader>,
138+
block_2: Option<&BlockHeader>,
135139
) -> Result<(), InvalidForkChoice> {
136140
// We don't need to perform the check if the hashes are null
137141
match (block_1, block_2) {

crates/networking/rpc/eth/block.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ impl RpcHandler for GetBlobBaseFee {
312312
_ => return Err(RpcErr::Internal("Could not get block header".to_owned())),
313313
};
314314
let parent_header = match find_parent_header(&header, &context.storage) {
315-
Ok(header) => header,
315+
Ok(option_header) => option_header,
316316
Err(error) => return Err(RpcErr::Internal(error.to_string())),
317317
};
318318

0 commit comments

Comments
 (0)