mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: update el requests for devnet 4 (#11865)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
@ -18,6 +18,7 @@ reth-primitives.workspace = true
|
||||
reth-consensus.workspace = true
|
||||
|
||||
# alloy
|
||||
alloy-eips.workspace = true
|
||||
alloy-primitives.workspace = true
|
||||
alloy-consensus.workspace = true
|
||||
|
||||
|
||||
@ -121,11 +121,11 @@ impl<ChainSpec: Send + Sync + EthChainSpec + EthereumHardforks + Debug> Consensu
|
||||
}
|
||||
|
||||
if self.chain_spec.is_prague_active_at_timestamp(header.timestamp) {
|
||||
if header.requests_root.is_none() {
|
||||
return Err(ConsensusError::RequestsRootMissing)
|
||||
if header.requests_hash.is_none() {
|
||||
return Err(ConsensusError::RequestsHashMissing)
|
||||
}
|
||||
} else if header.requests_root.is_some() {
|
||||
return Err(ConsensusError::RequestsRootUnexpected)
|
||||
} else if header.requests_hash.is_some() {
|
||||
return Err(ConsensusError::RequestsHashUnexpected)
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
use alloy_eips::eip7685::Requests;
|
||||
use alloy_primitives::{Bloom, B256};
|
||||
use reth_chainspec::EthereumHardforks;
|
||||
use reth_consensus::ConsensusError;
|
||||
use reth_primitives::{gas_spent_by_transactions, BlockWithSenders, GotExpected, Receipt, Request};
|
||||
use reth_primitives::{gas_spent_by_transactions, BlockWithSenders, GotExpected, Receipt};
|
||||
|
||||
/// Validate a block with regard to execution results:
|
||||
///
|
||||
@ -11,7 +12,7 @@ pub fn validate_block_post_execution<ChainSpec: EthereumHardforks>(
|
||||
block: &BlockWithSenders,
|
||||
chain_spec: &ChainSpec,
|
||||
receipts: &[Receipt],
|
||||
requests: &[Request],
|
||||
requests: &Requests,
|
||||
) -> Result<(), ConsensusError> {
|
||||
// Check if gas used matches the value set in header.
|
||||
let cumulative_gas_used =
|
||||
@ -36,15 +37,15 @@ pub fn validate_block_post_execution<ChainSpec: EthereumHardforks>(
|
||||
}
|
||||
}
|
||||
|
||||
// Validate that the header requests root matches the calculated requests root
|
||||
// Validate that the header requests hash matches the calculated requests hash
|
||||
if chain_spec.is_prague_active_at_timestamp(block.timestamp) {
|
||||
let Some(header_requests_root) = block.header.requests_root else {
|
||||
return Err(ConsensusError::RequestsRootMissing)
|
||||
let Some(header_requests_hash) = block.header.requests_hash else {
|
||||
return Err(ConsensusError::RequestsHashMissing)
|
||||
};
|
||||
let requests_root = reth_primitives::proofs::calculate_requests_root(requests);
|
||||
if requests_root != header_requests_root {
|
||||
return Err(ConsensusError::BodyRequestsRootDiff(
|
||||
GotExpected::new(requests_root, header_requests_root).into(),
|
||||
let requests_hash = requests.requests_hash();
|
||||
if requests_hash != header_requests_hash {
|
||||
return Err(ConsensusError::BodyRequestsHashDiff(
|
||||
GotExpected::new(requests_hash, header_requests_hash).into(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
//! Contains types required for building a payload.
|
||||
|
||||
use alloy_eips::eip4844::BlobTransactionSidecar;
|
||||
use alloy_eips::{eip4844::BlobTransactionSidecar, eip7685::Requests};
|
||||
use alloy_primitives::{Address, B256, U256};
|
||||
use alloy_rlp::Encodable;
|
||||
use alloy_rpc_types_engine::{
|
||||
@ -11,8 +11,7 @@ use reth_chain_state::ExecutedBlock;
|
||||
use reth_payload_primitives::{BuiltPayload, PayloadBuilderAttributes};
|
||||
use reth_primitives::{SealedBlock, Withdrawals};
|
||||
use reth_rpc_types_compat::engine::payload::{
|
||||
block_to_payload_v1, block_to_payload_v3, block_to_payload_v4,
|
||||
convert_block_to_payload_field_v2,
|
||||
block_to_payload_v1, block_to_payload_v3, convert_block_to_payload_field_v2,
|
||||
};
|
||||
use std::convert::Infallible;
|
||||
|
||||
@ -142,10 +141,17 @@ impl From<EthBuiltPayload> for ExecutionPayloadEnvelopeV3 {
|
||||
|
||||
impl From<EthBuiltPayload> for ExecutionPayloadEnvelopeV4 {
|
||||
fn from(value: EthBuiltPayload) -> Self {
|
||||
let EthBuiltPayload { block, fees, sidecars, .. } = value;
|
||||
let EthBuiltPayload { block, fees, sidecars, executed_block, .. } = value;
|
||||
|
||||
// if we have an executed block, we pop off the first set of requests from the execution
|
||||
// outcome. the assumption here is that there will always only be one block in the execution
|
||||
// outcome.
|
||||
let execution_requests = executed_block
|
||||
.and_then(|block| block.execution_outcome().requests.first().cloned())
|
||||
.map(Requests::take)
|
||||
.unwrap_or_default();
|
||||
Self {
|
||||
execution_payload: block_to_payload_v4(block),
|
||||
execution_payload: block_to_payload_v3(block),
|
||||
block_value: fees,
|
||||
// From the engine API spec:
|
||||
//
|
||||
@ -157,6 +163,7 @@ impl From<EthBuiltPayload> for ExecutionPayloadEnvelopeV4 {
|
||||
// <https://github.com/ethereum/execution-apis/blob/fe8e13c288c592ec154ce25c534e26cb7ce0530d/src/engine/cancun.md#specification-2>
|
||||
should_override_builder: false,
|
||||
blobs_bundle: sidecars.into_iter().map(Into::into).collect::<Vec<_>>().into(),
|
||||
execution_requests,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
//! EIP-6110 deposit requests parsing
|
||||
use alloc::{string::ToString, vec::Vec};
|
||||
use alloy_eips::eip6110::{DepositRequest, MAINNET_DEPOSIT_CONTRACT_ADDRESS};
|
||||
use alloy_primitives::Log;
|
||||
use alloy_eips::eip6110::MAINNET_DEPOSIT_CONTRACT_ADDRESS;
|
||||
use alloy_primitives::{Bytes, Log};
|
||||
use alloy_sol_types::{sol, SolEvent};
|
||||
use reth_chainspec::ChainSpec;
|
||||
use reth_evm::execute::BlockValidationError;
|
||||
use reth_primitives::{Receipt, Request};
|
||||
use reth_primitives::Receipt;
|
||||
|
||||
sol! {
|
||||
#[allow(missing_docs)]
|
||||
@ -20,73 +20,57 @@ sol! {
|
||||
|
||||
/// Parse [deposit contract](https://etherscan.io/address/0x00000000219ab540356cbb839cbe05303d7705fa)
|
||||
/// (address is from the passed [`ChainSpec`]) deposits from receipts, and return them as a
|
||||
/// [vector](Vec) of (requests)[Request].
|
||||
/// [vector](Vec) of (requests)[`alloy_eips::eip7685::Requests`].
|
||||
pub fn parse_deposits_from_receipts<'a, I>(
|
||||
chain_spec: &ChainSpec,
|
||||
receipts: I,
|
||||
) -> Result<Vec<Request>, BlockValidationError>
|
||||
) -> Result<Bytes, BlockValidationError>
|
||||
where
|
||||
I: IntoIterator<Item = &'a Receipt>,
|
||||
{
|
||||
let mut requests = Vec::new();
|
||||
let deposit_contract_address = chain_spec
|
||||
.deposit_contract
|
||||
.as_ref()
|
||||
.map_or(MAINNET_DEPOSIT_CONTRACT_ADDRESS, |contract| contract.address);
|
||||
receipts
|
||||
let logs: Vec<_> = receipts
|
||||
.into_iter()
|
||||
.flat_map(|receipt| receipt.logs.iter())
|
||||
// No need to filter for topic because there's only one event and that's the Deposit event
|
||||
// in the deposit contract.
|
||||
.flat_map(|receipt| &receipt.logs)
|
||||
// No need to filter for topic because there's only one event and that's the Deposit
|
||||
// event in the deposit contract.
|
||||
.filter(|log| log.address == deposit_contract_address)
|
||||
.map(|log| {
|
||||
let decoded_log = DepositEvent::decode_log(log, false)?;
|
||||
let deposit = parse_deposit_from_log(&decoded_log);
|
||||
Ok(Request::DepositRequest(deposit))
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|err: alloy_sol_types::Error| {
|
||||
BlockValidationError::DepositRequestDecode(err.to_string())
|
||||
})
|
||||
.collect();
|
||||
|
||||
for log in &logs {
|
||||
let decoded_log =
|
||||
DepositEvent::decode_log(log, false).map_err(|err: alloy_sol_types::Error| {
|
||||
BlockValidationError::DepositRequestDecode(err.to_string())
|
||||
})?;
|
||||
requests.extend(parse_deposit_from_log(&decoded_log).as_ref())
|
||||
}
|
||||
|
||||
Ok(requests.into())
|
||||
}
|
||||
|
||||
fn parse_deposit_from_log(log: &Log<DepositEvent>) -> DepositRequest {
|
||||
fn parse_deposit_from_log(log: &Log<DepositEvent>) -> Bytes {
|
||||
// SAFETY: These `expect` https://github.com/ethereum/consensus-specs/blob/5f48840f4d768bf0e0a8156a3ed06ec333589007/solidity_deposit_contract/deposit_contract.sol#L107-L110
|
||||
// are safe because the `DepositEvent` is the only event in the deposit contract and the length
|
||||
// checks are done there.
|
||||
DepositRequest {
|
||||
pubkey: log
|
||||
.pubkey
|
||||
.as_ref()
|
||||
.try_into()
|
||||
.expect("pubkey length should be enforced in deposit contract"),
|
||||
withdrawal_credentials: log
|
||||
.withdrawal_credentials
|
||||
.as_ref()
|
||||
.try_into()
|
||||
.expect("withdrawal_credentials length should be enforced in deposit contract"),
|
||||
amount: u64::from_le_bytes(
|
||||
log.amount
|
||||
.as_ref()
|
||||
.try_into()
|
||||
.expect("amount length should be enforced in deposit contract"),
|
||||
),
|
||||
signature: log
|
||||
.signature
|
||||
.as_ref()
|
||||
.try_into()
|
||||
.expect("signature length should be enforced in deposit contract"),
|
||||
index: u64::from_le_bytes(
|
||||
log.index
|
||||
.as_ref()
|
||||
.try_into()
|
||||
.expect("deposit index length should be enforced in deposit contract"),
|
||||
),
|
||||
}
|
||||
[
|
||||
log.pubkey.as_ref(),
|
||||
log.withdrawal_credentials.as_ref(),
|
||||
log.amount.as_ref(),
|
||||
log.signature.as_ref(),
|
||||
log.index.as_ref(),
|
||||
]
|
||||
.concat()
|
||||
.into()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use alloy_primitives::bytes;
|
||||
use reth_chainspec::MAINNET;
|
||||
use reth_primitives::TxType;
|
||||
|
||||
@ -119,9 +103,12 @@ mod tests {
|
||||
},
|
||||
];
|
||||
|
||||
let requests = parse_deposits_from_receipts(&MAINNET, &receipts).unwrap();
|
||||
assert_eq!(requests.len(), 2);
|
||||
assert_eq!(requests[0].as_deposit_request().unwrap().amount, 32e9 as u64);
|
||||
assert_eq!(requests[1].as_deposit_request().unwrap().amount, 32e9 as u64);
|
||||
let request_data = parse_deposits_from_receipts(&MAINNET, &receipts).unwrap();
|
||||
assert_eq!(
|
||||
request_data,
|
||||
bytes!(
|
||||
"998c8086669bf65e24581cda47d8537966e9f5066fc6ffdcba910a1bfb91eae7a4873fcce166a1c4ea217e6b1afd396201000000000000000000000001c340fb72ed14d4eaa71f7633ee9e33b88d4f39004059730700000098ddbffd700c1aac324cfdf0492ff289223661eb26718ce3651ba2469b22f480d56efab432ed91af05a006bde0c1ea68134e0acd8cacca0c13ad1f716db874b44abfcc966368019753174753bca3af2ea84bc569c46f76592a91e97f311eddece474160000000000a1a2ba870a90e889aa594a0cc1c6feffb94c2d8f65646c937f1f456a315ef649533e25a4614d8f4f66ebdb06481b90af0100000000000000000000000a0f04a231efbc29e1db7d086300ff550211c2f60040597307000000ad416d590e1a7f52baff770a12835b68904efad22cc9f8ba531e50cbbd26f32b9c7373cf6538a0577f501e4d3e3e63e208767bcccaae94e1e3720bfb734a286f9c017d17af46536545ccb7ca94d71f295e71f6d25bf978c09ada6f8d3f7ba039e374160000000000"
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,8 +4,9 @@ use crate::{
|
||||
dao_fork::{DAO_HARDFORK_BENEFICIARY, DAO_HARDKFORK_ACCOUNTS},
|
||||
EthEvmConfig,
|
||||
};
|
||||
use alloc::{boxed::Box, sync::Arc, vec, vec::Vec};
|
||||
use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
||||
use alloy_consensus::Transaction as _;
|
||||
use alloy_eips::eip7685::Requests;
|
||||
use alloy_primitives::{BlockNumber, U256};
|
||||
use core::fmt::Display;
|
||||
use reth_chainspec::{ChainSpec, EthereumHardforks, MAINNET};
|
||||
@ -19,7 +20,7 @@ use reth_evm::{
|
||||
ConfigureEvm,
|
||||
};
|
||||
use reth_execution_types::ExecutionOutcome;
|
||||
use reth_primitives::{BlockWithSenders, EthereumHardfork, Header, Receipt, Request};
|
||||
use reth_primitives::{BlockWithSenders, EthereumHardfork, Header, Receipt};
|
||||
use reth_prune_types::PruneModes;
|
||||
use reth_revm::{
|
||||
batch::BlockBatchRecord,
|
||||
@ -104,7 +105,7 @@ where
|
||||
#[derive(Debug, Clone)]
|
||||
struct EthExecuteOutput {
|
||||
receipts: Vec<Receipt>,
|
||||
requests: Vec<Request>,
|
||||
requests: Requests,
|
||||
gas_used: u64,
|
||||
}
|
||||
|
||||
@ -122,7 +123,7 @@ where
|
||||
EvmConfig: ConfigureEvm<Header = Header>,
|
||||
{
|
||||
/// Executes the transactions in the block and returns the receipts of the transactions in the
|
||||
/// block, the total gas used and the list of EIP-7685 [requests](Request).
|
||||
/// block, the total gas used and the list of EIP-7685 [requests](Requests).
|
||||
///
|
||||
/// This applies the pre-execution and post-execution changes that require an [EVM](Evm), and
|
||||
/// executes the transactions.
|
||||
@ -205,11 +206,11 @@ where
|
||||
let deposit_requests =
|
||||
crate::eip6110::parse_deposits_from_receipts(&self.chain_spec, &receipts)?;
|
||||
|
||||
let post_execution_requests = system_caller.apply_post_execution_changes(&mut evm)?;
|
||||
|
||||
[deposit_requests, post_execution_requests].concat()
|
||||
let mut requests = Requests::new(vec![deposit_requests]);
|
||||
requests.extend(system_caller.apply_post_execution_changes(&mut evm)?);
|
||||
requests
|
||||
} else {
|
||||
vec![]
|
||||
Requests::default()
|
||||
};
|
||||
|
||||
Ok(EthExecuteOutput { receipts, requests, gas_used: cumulative_gas_used })
|
||||
@ -283,7 +284,7 @@ where
|
||||
/// Execute a single block and apply the state changes to the internal state.
|
||||
///
|
||||
/// Returns the receipts of the transactions in the block, the total gas used and the list of
|
||||
/// EIP-7685 [requests](Request).
|
||||
/// EIP-7685 [requests](Requests).
|
||||
///
|
||||
/// Returns an error if execution fails.
|
||||
fn execute_without_verification_with_state_hook<F>(
|
||||
@ -494,11 +495,12 @@ where
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use alloy_consensus::{TxLegacy, EMPTY_ROOT_HASH};
|
||||
use alloy_consensus::TxLegacy;
|
||||
use alloy_eips::{
|
||||
eip2935::{HISTORY_STORAGE_ADDRESS, HISTORY_STORAGE_CODE},
|
||||
eip4788::{BEACON_ROOTS_ADDRESS, BEACON_ROOTS_CODE, SYSTEM_ADDRESS},
|
||||
eip7002::{WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS, WITHDRAWAL_REQUEST_PREDEPLOY_CODE},
|
||||
eip7685::EMPTY_REQUESTS_HASH,
|
||||
};
|
||||
use alloy_primitives::{b256, fixed_bytes, keccak256, Bytes, TxKind, B256};
|
||||
use reth_chainspec::{ChainSpecBuilder, ForkCondition};
|
||||
@ -583,7 +585,6 @@ mod tests {
|
||||
transactions: vec![],
|
||||
ommers: vec![],
|
||||
withdrawals: None,
|
||||
requests: None,
|
||||
},
|
||||
},
|
||||
senders: vec![],
|
||||
@ -612,12 +613,7 @@ mod tests {
|
||||
&BlockWithSenders {
|
||||
block: Block {
|
||||
header: header.clone(),
|
||||
body: BlockBody {
|
||||
transactions: vec![],
|
||||
ommers: vec![],
|
||||
withdrawals: None,
|
||||
requests: None,
|
||||
},
|
||||
body: BlockBody { transactions: vec![], ommers: vec![], withdrawals: None },
|
||||
},
|
||||
senders: vec![],
|
||||
},
|
||||
@ -684,7 +680,6 @@ mod tests {
|
||||
transactions: vec![],
|
||||
ommers: vec![],
|
||||
withdrawals: None,
|
||||
requests: None,
|
||||
},
|
||||
},
|
||||
senders: vec![],
|
||||
@ -739,7 +734,6 @@ mod tests {
|
||||
transactions: vec![],
|
||||
ommers: vec![],
|
||||
withdrawals: None,
|
||||
requests: None,
|
||||
},
|
||||
},
|
||||
senders: vec![],
|
||||
@ -1016,7 +1010,7 @@ mod tests {
|
||||
parent_hash: B256::random(),
|
||||
timestamp: 1,
|
||||
number: fork_activation_block,
|
||||
requests_root: Some(EMPTY_ROOT_HASH),
|
||||
requests_hash: Some(EMPTY_REQUESTS_HASH),
|
||||
..Header::default()
|
||||
};
|
||||
let provider = executor_provider(chain_spec);
|
||||
@ -1075,7 +1069,7 @@ mod tests {
|
||||
parent_hash: B256::random(),
|
||||
timestamp: 1,
|
||||
number: fork_activation_block,
|
||||
requests_root: Some(EMPTY_ROOT_HASH),
|
||||
requests_hash: Some(EMPTY_REQUESTS_HASH),
|
||||
..Header::default()
|
||||
};
|
||||
|
||||
@ -1121,7 +1115,7 @@ mod tests {
|
||||
);
|
||||
|
||||
let mut header = chain_spec.genesis_header().clone();
|
||||
header.requests_root = Some(EMPTY_ROOT_HASH);
|
||||
header.requests_hash = Some(EMPTY_REQUESTS_HASH);
|
||||
let header_hash = header.hash_slow();
|
||||
|
||||
let provider = executor_provider(chain_spec);
|
||||
@ -1159,7 +1153,7 @@ mod tests {
|
||||
parent_hash: header_hash,
|
||||
timestamp: 1,
|
||||
number: 1,
|
||||
requests_root: Some(EMPTY_ROOT_HASH),
|
||||
requests_hash: Some(EMPTY_REQUESTS_HASH),
|
||||
..Header::default()
|
||||
};
|
||||
let header_hash = header.hash_slow();
|
||||
@ -1196,7 +1190,7 @@ mod tests {
|
||||
parent_hash: header_hash,
|
||||
timestamp: 1,
|
||||
number: 2,
|
||||
requests_root: Some(EMPTY_ROOT_HASH),
|
||||
requests_hash: Some(EMPTY_REQUESTS_HASH),
|
||||
..Header::default()
|
||||
};
|
||||
|
||||
@ -1254,15 +1248,16 @@ mod tests {
|
||||
HashMap::default(),
|
||||
);
|
||||
|
||||
// https://github.com/lightclient/7002asm/blob/e0d68e04d15f25057af7b6d180423d94b6b3bdb3/test/Contract.t.sol.in#L49-L64
|
||||
// https://github.com/lightclient/sys-asm/blob/9282bdb9fd64e024e27f60f507486ffb2183cba2/test/Withdrawal.t.sol.in#L36
|
||||
let validator_public_key = fixed_bytes!("111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
|
||||
let withdrawal_amount = fixed_bytes!("2222222222222222");
|
||||
let withdrawal_amount = fixed_bytes!("0203040506070809");
|
||||
let input: Bytes = [&validator_public_key[..], &withdrawal_amount[..]].concat().into();
|
||||
assert_eq!(input.len(), 56);
|
||||
|
||||
let mut header = chain_spec.genesis_header().clone();
|
||||
header.gas_limit = 1_500_000;
|
||||
header.gas_used = 134_807;
|
||||
// measured
|
||||
header.gas_used = 135_856;
|
||||
header.receipts_root =
|
||||
b256!("b31a3e47b902e9211c4d349af4e4c5604ce388471e79ca008907ae4616bb0ed3");
|
||||
|
||||
@ -1272,10 +1267,10 @@ mod tests {
|
||||
chain_id: Some(chain_spec.chain.id()),
|
||||
nonce: 1,
|
||||
gas_price: header.base_fee_per_gas.unwrap().into(),
|
||||
gas_limit: 134_807,
|
||||
gas_limit: header.gas_used,
|
||||
to: TxKind::Call(WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS),
|
||||
// `MIN_WITHDRAWAL_REQUEST_FEE`
|
||||
value: U256::from(1),
|
||||
value: U256::from(2),
|
||||
input,
|
||||
}),
|
||||
);
|
||||
@ -1302,11 +1297,9 @@ mod tests {
|
||||
let receipt = receipts.first().unwrap();
|
||||
assert!(receipt.success);
|
||||
|
||||
let request = requests.first().unwrap();
|
||||
let withdrawal_request = request.as_withdrawal_request().unwrap();
|
||||
assert_eq!(withdrawal_request.source_address, sender_address);
|
||||
assert_eq!(withdrawal_request.validator_pubkey, validator_public_key);
|
||||
assert_eq!(withdrawal_request.amount, u64::from_be_bytes(withdrawal_amount.into()));
|
||||
assert!(requests[0].is_empty(), "there should be no deposits");
|
||||
assert!(!requests[1].is_empty(), "there should be a withdrawal");
|
||||
assert!(requests[2].is_empty(), "there should be no consolidations");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@ -6,6 +6,7 @@ use crate::{
|
||||
};
|
||||
use alloc::sync::Arc;
|
||||
use alloy_consensus::Transaction as _;
|
||||
use alloy_eips::eip7685::Requests;
|
||||
use core::fmt::Display;
|
||||
use reth_chainspec::{ChainSpec, EthereumHardfork, EthereumHardforks, MAINNET};
|
||||
use reth_consensus::ConsensusError;
|
||||
@ -18,7 +19,7 @@ use reth_evm::{
|
||||
system_calls::{OnStateHook, SystemCaller},
|
||||
ConfigureEvm, ConfigureEvmEnv,
|
||||
};
|
||||
use reth_primitives::{BlockWithSenders, Header, Receipt, Request};
|
||||
use reth_primitives::{BlockWithSenders, Header, Receipt};
|
||||
use reth_revm::{
|
||||
db::{states::bundle_state::BundleRetention, BundleState},
|
||||
state_change::post_block_balance_increments,
|
||||
@ -194,7 +195,7 @@ where
|
||||
block: &BlockWithSenders,
|
||||
total_difficulty: U256,
|
||||
receipts: &[Receipt],
|
||||
) -> Result<Vec<Request>, Self::Error> {
|
||||
) -> Result<Requests, Self::Error> {
|
||||
let env = self.evm_env_for_block(&block.header, total_difficulty);
|
||||
let mut evm = self.evm_config.evm_with_env(&mut self.state, env);
|
||||
|
||||
@ -203,12 +204,11 @@ where
|
||||
let deposit_requests =
|
||||
crate::eip6110::parse_deposits_from_receipts(&self.chain_spec, receipts)?;
|
||||
|
||||
let post_execution_requests =
|
||||
self.system_caller.apply_post_execution_changes(&mut evm)?;
|
||||
|
||||
[deposit_requests, post_execution_requests].concat()
|
||||
let mut requests = Requests::new(vec![deposit_requests]);
|
||||
requests.extend(self.system_caller.apply_post_execution_changes(&mut evm)?);
|
||||
requests
|
||||
} else {
|
||||
vec![]
|
||||
Requests::default()
|
||||
};
|
||||
drop(evm);
|
||||
|
||||
@ -257,7 +257,7 @@ where
|
||||
&self,
|
||||
block: &BlockWithSenders,
|
||||
receipts: &[Receipt],
|
||||
requests: &[Request],
|
||||
requests: &Requests,
|
||||
) -> Result<(), ConsensusError> {
|
||||
validate_block_post_execution(block, &self.chain_spec.clone(), receipts, requests)
|
||||
}
|
||||
@ -266,11 +266,12 @@ where
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use alloy_consensus::{TxLegacy, EMPTY_ROOT_HASH};
|
||||
use alloy_consensus::TxLegacy;
|
||||
use alloy_eips::{
|
||||
eip2935::{HISTORY_STORAGE_ADDRESS, HISTORY_STORAGE_CODE},
|
||||
eip4788::{BEACON_ROOTS_ADDRESS, BEACON_ROOTS_CODE, SYSTEM_ADDRESS},
|
||||
eip7002::{WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS, WITHDRAWAL_REQUEST_PREDEPLOY_CODE},
|
||||
eip7685::EMPTY_REQUESTS_HASH,
|
||||
};
|
||||
use alloy_primitives::{b256, fixed_bytes, keccak256, Bytes, TxKind, B256};
|
||||
use reth_chainspec::{ChainSpecBuilder, ForkCondition};
|
||||
@ -365,7 +366,6 @@ mod tests {
|
||||
transactions: vec![],
|
||||
ommers: vec![],
|
||||
withdrawals: None,
|
||||
requests: None,
|
||||
},
|
||||
},
|
||||
senders: vec![],
|
||||
@ -397,7 +397,6 @@ mod tests {
|
||||
transactions: vec![],
|
||||
ommers: vec![],
|
||||
withdrawals: None,
|
||||
requests: None,
|
||||
},
|
||||
},
|
||||
senders: vec![],
|
||||
@ -468,7 +467,6 @@ mod tests {
|
||||
transactions: vec![],
|
||||
ommers: vec![],
|
||||
withdrawals: None,
|
||||
requests: None,
|
||||
},
|
||||
},
|
||||
senders: vec![],
|
||||
@ -523,7 +521,6 @@ mod tests {
|
||||
transactions: vec![],
|
||||
ommers: vec![],
|
||||
withdrawals: None,
|
||||
requests: None,
|
||||
},
|
||||
},
|
||||
senders: vec![],
|
||||
@ -797,7 +794,7 @@ mod tests {
|
||||
parent_hash: B256::random(),
|
||||
timestamp: 1,
|
||||
number: fork_activation_block,
|
||||
requests_root: Some(EMPTY_ROOT_HASH),
|
||||
requests_hash: Some(EMPTY_REQUESTS_HASH),
|
||||
..Header::default()
|
||||
};
|
||||
let provider = executor_provider(chain_spec);
|
||||
@ -855,7 +852,7 @@ mod tests {
|
||||
parent_hash: B256::random(),
|
||||
timestamp: 1,
|
||||
number: fork_activation_block,
|
||||
requests_root: Some(EMPTY_ROOT_HASH),
|
||||
requests_hash: Some(EMPTY_REQUESTS_HASH),
|
||||
..Header::default()
|
||||
};
|
||||
|
||||
@ -901,7 +898,7 @@ mod tests {
|
||||
);
|
||||
|
||||
let mut header = chain_spec.genesis_header().clone();
|
||||
header.requests_root = Some(EMPTY_ROOT_HASH);
|
||||
header.requests_hash = Some(EMPTY_REQUESTS_HASH);
|
||||
let header_hash = header.hash_slow();
|
||||
|
||||
let provider = executor_provider(chain_spec);
|
||||
@ -938,7 +935,7 @@ mod tests {
|
||||
parent_hash: header_hash,
|
||||
timestamp: 1,
|
||||
number: 1,
|
||||
requests_root: Some(EMPTY_ROOT_HASH),
|
||||
requests_hash: Some(EMPTY_REQUESTS_HASH),
|
||||
..Header::default()
|
||||
};
|
||||
let header_hash = header.hash_slow();
|
||||
@ -977,7 +974,7 @@ mod tests {
|
||||
parent_hash: header_hash,
|
||||
timestamp: 1,
|
||||
number: 2,
|
||||
requests_root: Some(EMPTY_ROOT_HASH),
|
||||
requests_hash: Some(EMPTY_REQUESTS_HASH),
|
||||
..Header::default()
|
||||
};
|
||||
|
||||
@ -1039,15 +1036,16 @@ mod tests {
|
||||
HashMap::default(),
|
||||
);
|
||||
|
||||
// https://github.com/lightclient/7002asm/blob/e0d68e04d15f25057af7b6d180423d94b6b3bdb3/test/Contract.t.sol.in#L49-L64
|
||||
// https://github.com/lightclient/sys-asm/blob/9282bdb9fd64e024e27f60f507486ffb2183cba2/test/Withdrawal.t.sol.in#L36
|
||||
let validator_public_key = fixed_bytes!("111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
|
||||
let withdrawal_amount = fixed_bytes!("2222222222222222");
|
||||
let withdrawal_amount = fixed_bytes!("0203040506070809");
|
||||
let input: Bytes = [&validator_public_key[..], &withdrawal_amount[..]].concat().into();
|
||||
assert_eq!(input.len(), 56);
|
||||
|
||||
let mut header = chain_spec.genesis_header().clone();
|
||||
header.gas_limit = 1_500_000;
|
||||
header.gas_used = 134_807;
|
||||
// measured
|
||||
header.gas_used = 135_856;
|
||||
header.receipts_root =
|
||||
b256!("b31a3e47b902e9211c4d349af4e4c5604ce388471e79ca008907ae4616bb0ed3");
|
||||
|
||||
@ -1057,10 +1055,10 @@ mod tests {
|
||||
chain_id: Some(chain_spec.chain.id()),
|
||||
nonce: 1,
|
||||
gas_price: header.base_fee_per_gas.unwrap().into(),
|
||||
gas_limit: 134_807,
|
||||
gas_limit: header.gas_used,
|
||||
to: TxKind::Call(WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS),
|
||||
// `MIN_WITHDRAWAL_REQUEST_FEE`
|
||||
value: U256::from(1),
|
||||
value: U256::from(2),
|
||||
input,
|
||||
}),
|
||||
);
|
||||
@ -1087,11 +1085,9 @@ mod tests {
|
||||
let receipt = receipts.first().unwrap();
|
||||
assert!(receipt.success);
|
||||
|
||||
let request = requests.first().unwrap();
|
||||
let withdrawal_request = request.as_withdrawal_request().unwrap();
|
||||
assert_eq!(withdrawal_request.source_address, sender_address);
|
||||
assert_eq!(withdrawal_request.validator_pubkey, validator_public_key);
|
||||
assert_eq!(withdrawal_request.amount, u64::from_be_bytes(withdrawal_amount.into()));
|
||||
assert!(requests[0].is_empty(), "there should be no deposits");
|
||||
assert!(!requests[1].is_empty(), "there should be a withdrawal");
|
||||
assert!(requests[2].is_empty(), "there should be no consolidations");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@ -33,8 +33,9 @@ revm.workspace = true
|
||||
revm-primitives.workspace = true
|
||||
|
||||
# alloy
|
||||
alloy-primitives.workspace = true
|
||||
alloy-eips.workspace = true
|
||||
alloy-consensus.workspace = true
|
||||
alloy-primitives.workspace = true
|
||||
|
||||
# misc
|
||||
tracing.workspace = true
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
#![allow(clippy::useless_let_if_seq)]
|
||||
|
||||
use alloy_consensus::EMPTY_OMMER_ROOT_HASH;
|
||||
use alloy_eips::eip7685::Requests;
|
||||
use alloy_primitives::U256;
|
||||
use reth_basic_payload_builder::{
|
||||
commit_withdrawals, is_better_payload, BuildArguments, BuildOutcome, PayloadBuilder,
|
||||
@ -25,7 +26,7 @@ use reth_payload_builder::{EthBuiltPayload, EthPayloadBuilderAttributes};
|
||||
use reth_payload_primitives::{PayloadBuilderAttributes, PayloadBuilderError};
|
||||
use reth_primitives::{
|
||||
constants::{eip4844::MAX_DATA_GAS_PER_BLOCK, BEACON_NONCE},
|
||||
proofs::{self, calculate_requests_root},
|
||||
proofs::{self},
|
||||
revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg},
|
||||
Block, BlockBody, EthereumHardforks, Header, Receipt,
|
||||
};
|
||||
@ -308,9 +309,7 @@ where
|
||||
}
|
||||
|
||||
// calculate the requests and the requests root
|
||||
let (requests, requests_root) = if chain_spec
|
||||
.is_prague_active_at_timestamp(attributes.timestamp)
|
||||
{
|
||||
let requests = if chain_spec.is_prague_active_at_timestamp(attributes.timestamp) {
|
||||
let deposit_requests = parse_deposits_from_receipts(&chain_spec, receipts.iter().flatten())
|
||||
.map_err(|err| PayloadBuilderError::Internal(RethError::Execution(err.into())))?;
|
||||
let withdrawal_requests = system_caller
|
||||
@ -328,11 +327,9 @@ where
|
||||
)
|
||||
.map_err(|err| PayloadBuilderError::Internal(err.into()))?;
|
||||
|
||||
let requests = [deposit_requests, withdrawal_requests, consolidation_requests].concat();
|
||||
let requests_root = calculate_requests_root(&requests);
|
||||
(Some(requests.into()), Some(requests_root))
|
||||
Some(Requests::new(vec![deposit_requests, withdrawal_requests, consolidation_requests]))
|
||||
} else {
|
||||
(None, None)
|
||||
None
|
||||
};
|
||||
|
||||
let WithdrawalsOutcome { withdrawals_root, withdrawals } =
|
||||
@ -414,13 +411,13 @@ where
|
||||
parent_beacon_block_root: attributes.parent_beacon_block_root,
|
||||
blob_gas_used: blob_gas_used.map(Into::into),
|
||||
excess_blob_gas: excess_blob_gas.map(Into::into),
|
||||
requests_root,
|
||||
requests_hash: requests.map(|r| r.requests_hash()),
|
||||
};
|
||||
|
||||
// seal the block
|
||||
let block = Block {
|
||||
header,
|
||||
body: BlockBody { transactions: executed_txs, ommers: vec![], withdrawals, requests },
|
||||
body: BlockBody { transactions: executed_txs, ommers: vec![], withdrawals },
|
||||
};
|
||||
|
||||
let sealed_block = block.seal_slow();
|
||||
|
||||
Reference in New Issue
Block a user