Skip to content

Commit 3a11020

Browse files
0xClandestinegrandizzymattsse
authored
feat(cheats): add vm.getRawBlockHeader(blockNumber) (#11082)
* feat: add `getRawBlockHeader` cheat * Update testdata/default/cheats/GetRawBlockHeader.t.sol Co-authored-by: Matthias Seitz <[email protected]> * Update testdata/default/cheats/GetRawBlockHeader.t.sol Co-authored-by: Matthias Seitz <[email protected]> * Fix fmt --------- Co-authored-by: grandizzy <[email protected]> Co-authored-by: Matthias Seitz <[email protected]> Co-authored-by: grandizzy <[email protected]>
1 parent 575279d commit 3a11020

File tree

5 files changed

+71
-0
lines changed

5 files changed

+71
-0
lines changed

crates/cheatcodes/assets/cheatcodes.json

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/cheatcodes/spec/src/vm.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,11 @@ interface Vm {
522522
#[cheatcode(group = Evm, safety = Safe)]
523523
function getBlockTimestamp() external view returns (uint256 timestamp);
524524

525+
/// Gets the RLP encoded block header for a given block number.
526+
/// Returns the block header in the same format as `cast block <block_number> --raw`.
527+
#[cheatcode(group = Evm, safety = Safe)]
528+
function getRawBlockHeader(uint256 blockNumber) external view returns (bytes memory rlpHeader);
529+
525530
/// Sets `block.blobbasefee`
526531
#[cheatcode(group = Evm, safety = Unsafe)]
527532
function blobBaseFee(uint256 newBlobBaseFee) external;

crates/cheatcodes/src/evm/fork.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,33 @@ impl Cheatcode for eth_getLogsCall {
266266
}
267267
}
268268

269+
impl Cheatcode for getRawBlockHeaderCall {
270+
fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
271+
let Self { blockNumber } = self;
272+
let url = ccx
273+
.ecx
274+
.journaled_state
275+
.database
276+
.active_fork_url()
277+
.ok_or_else(|| fmt_err!("no active fork"))?;
278+
let provider = ProviderBuilder::new(&url).build()?;
279+
let block_number = u64::try_from(blockNumber)
280+
.map_err(|_| fmt_err!("block number must be less than 2^64"))?;
281+
let block =
282+
foundry_common::block_on(async move { provider.get_block(block_number.into()).await })
283+
.map_err(|e| fmt_err!("failed to get block: {e}"))?
284+
.ok_or_else(|| fmt_err!("block {block_number} not found"))?;
285+
286+
let header: alloy_consensus::Header = block
287+
.into_inner()
288+
.header
289+
.inner
290+
.try_into_header()
291+
.map_err(|e| fmt_err!("failed to convert to header: {e}"))?;
292+
Ok(alloy_rlp::encode(&header).abi_encode())
293+
}
294+
}
295+
269296
/// Creates and then also selects the new fork
270297
fn create_select_fork(ccx: &mut CheatsCtxt, url_or_alias: &str, block: Option<u64>) -> Result {
271298
check_broadcast(ccx.state)?;

testdata/cheats/Vm.sol

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// SPDX-License-Identifier: MIT OR Apache-2.0
2+
pragma solidity ^0.8.18;
3+
4+
import "ds-test/test.sol";
5+
import "cheats/Vm.sol";
6+
7+
contract GetRawBlockHeaderTest is DSTest {
8+
Vm constant vm = Vm(HEVM_ADDRESS);
9+
10+
function testGetRawBlockHeaderWithFork() public {
11+
vm.createSelectFork("mainnet");
12+
assertEq(
13+
keccak256(vm.getRawBlockHeader(22985278)),
14+
// `cast keccak256 $(cast block 22985278 --raw)`
15+
0x492419d85d2817f50577807a287742fbdcaae00ce89f2ea885e419ee4493b00f
16+
);
17+
}
18+
}

0 commit comments

Comments
 (0)