feat: update el requests for devnet 4 (#11865)

Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
Oliver
2024-10-19 14:48:35 +02:00
committed by GitHub
parent 2ae93682b4
commit 3bd695ee63
106 changed files with 799 additions and 1328 deletions

View File

@ -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

View File

@ -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(())

View File

@ -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(),
))
}
}

View File

@ -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,
}
}
}

View File

@ -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"
)
);
}
}

View File

@ -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]

View File

@ -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]

View File

@ -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

View File

@ -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();