fix(evm): propagate state provider errors in the block assembler - #470
Closed
HusseinAdeiza wants to merge 1 commit into
Closed
HusseinAdeiza wants to merge 1 commit into
HusseinAdeiza wants to merge 1 commit into
Conversation
`ArcBlockAssembler::assemble_block` read the nextBaseFee slot with `unwrap_or(None)`, which collapses a `ProviderResult` error into "slot not set". The `else` branch then logged "Gas value not found" and left `extra_data` empty, so a transient DB or trie read failure on a proposer produced a block rather than a failed build. `validate_extra_data_base_fee` rejects any block whose `extra_data` does not decode to the computed nextBaseFee, so that block is rejected by every validator, and the only local trace is a warning that misdescribes an I/O failure as a missing value. Propagate the provider error instead. `assemble_block` already returns `Result<Self::Block, BlockExecutionError>`, so this needs no signature change, and it matches the existing use of `BlockExecutionError::other` in crates/evm/src/executor.rs. The genuine unset-slot case keeps its warning and continues; the two are now distinguishable. Add two tests: one asserting a provider error fails the build rather than yielding a block with empty `extra_data`, one asserting the unset-slot case still assembles. Closes: circlefin#438
HusseinAdeiza
requested review from
ZhiyuCircle,
ancazamfir,
romac and
sergio-mena
as code owners
September 27, 2026 01:28
Contributor
|
Contributor
|
Hi @HusseinAdeiza, Thank you for your interest in contributing to Arc Node. This PR has been automatically closed because you are not assigned to issue #438. We require contributors to be explicitly assigned to an issue before submitting a PR. To contribute properly:
Please see our CONTRIBUTING.md for more details. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ArcBlockAssembler::assemble_blockswallowed state provider errors when reading the nextBaseFee slot, turning a transient read failure into a block that every validator rejects.Details
In
crates/evm/src/assembler.rs, the slot read was:value = input .state_provider .storage(SYSTEM_ACCOUNTING_ADDRESS, slot) .unwrap_or(None)unwrap_or(None)collapses aProviderResulterror into "slot not set". Theelsebranch then logsGas value not found for block number: …and leavesinput.execution_ctx.extra_dataempty.The consequence is worse than a missing log line.
validate_extra_data_base_feeincrates/evm/src/executor.rs:267compares the decodedextra_dataagainst the computednextBaseFeeand returnsBlockExecutionError::Validationon any mismatch, including whenextra_datais empty. So a database or trie read failure on a proposer does not fail the build locally, it produces a block that is rejected by the entire network, and the only local trace is a warning that describes an I/O failure as a missing value.The fix propagates the error:
value = input .state_provider .storage(SYSTEM_ACCOUNTING_ADDRESS, slot) .map_err(BlockExecutionError::other)?assemble_blockalready returnsResult<Self::Block, BlockExecutionError>, so this needs no signature change and no new error type. It matches the existing use ofBlockExecutionError::otheratcrates/evm/src/executor.rs:188.The genuine unset-slot case is unchanged: it still logs the warning and assembles the block. The two conditions are now distinguishable, which is the point of the change.
Testing
Two tests added to the existing
mod testsincrates/evm/src/assembler.rs, both driving a realBlockAssemblerInputbuilt withBlockAssemblerInput::newagainstArcEvmConfig:assemble_block_fails_when_state_provider_errorsmakes the provider returnErrand assertsassemble_blockreturnsErr, and that the error is theProviderErroritself, not a generic wrapper. This is the regression test.assemble_block_warns_and_continues_when_slot_unsetmakes the provider returnOk(None)and asserts the build still succeeds with emptyextra_data, confirming the pre-existing warn-and-continue behaviour is intact.The stub provider implements only
storagewith real behaviour; every other method isunimplemented!(), so ifassemble_blockever reaches the provider through another path the test panics rather than silently passing.Sabotage check, to confirm the regression test is not vacuous. With
.unwrap_or(None)restored and nothing else changed, the error test fails:The failure output is the bug itself: on unfixed code the provider error produces
Okwithextra_data: 0x, the invalid block described above. With the fix restored, all three tests pass.Full crate suite and lint:
No changelog entry: recent fix commits on
maindo not touchCHANGELOG.md, which appears to be release-generated.Closes: #438