mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-31 21:27:12 +00:00
resolve merge conflicts
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
use crate::engine_api::{
|
||||
ExecutionBlock, PayloadAttributes, PayloadId, PayloadStatusV1, PayloadStatusV1Status,
|
||||
json_structures::{
|
||||
JsonForkchoiceUpdatedV1Response, JsonPayloadStatusV1, JsonPayloadStatusV1Status,
|
||||
BlobAndProof, BlobAndProofV1, BlobAndProofV2, JsonForkchoiceUpdatedV1Response,
|
||||
JsonPayloadStatusV1, JsonPayloadStatusV1Status,
|
||||
},
|
||||
};
|
||||
use crate::engines::ForkchoiceState;
|
||||
@@ -15,20 +16,20 @@ use rand::{Rng, SeedableRng, rngs::StdRng};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::Decode;
|
||||
use ssz_types::VariableList;
|
||||
use state_processing::per_block_processing::deneb::kzg_commitment_to_versioned_hash;
|
||||
use std::cmp::max;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tracing::warn;
|
||||
use tree_hash::TreeHash;
|
||||
use tree_hash_derive::TreeHash;
|
||||
use types::{
|
||||
Blob, ChainSpec, EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadBellatrix,
|
||||
ExecutionPayloadCapella, ExecutionPayloadDeneb, ExecutionPayloadEip7805,
|
||||
ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadGloas, ExecutionPayloadHeader,
|
||||
ForkName, Hash256, KzgProofs, Transaction, Transactions, Uint256,
|
||||
ExecutionRequests, ForkName, Hash256, KzgProofs, Transaction, Transactions, Uint256,
|
||||
};
|
||||
|
||||
use super::DEFAULT_TERMINAL_BLOCK;
|
||||
|
||||
const TEST_BLOB_BUNDLE: &[u8] = include_bytes!("fixtures/mainnet/test_blobs_bundle.ssz");
|
||||
const TEST_BLOB_BUNDLE_V2: &[u8] = include_bytes!("fixtures/mainnet/test_blobs_bundle_v2.ssz");
|
||||
|
||||
@@ -161,6 +162,14 @@ pub struct ExecutionBlockGenerator<E: EthSpec> {
|
||||
pub blobs_bundles: HashMap<PayloadId, BlobsBundle<E>>,
|
||||
pub kzg: Option<Arc<Kzg>>,
|
||||
rng: Arc<Mutex<StdRng>>,
|
||||
/*
|
||||
* Execution requests (electra+)
|
||||
*/
|
||||
/// Per-payload execution requests returned by `getPayload`.
|
||||
execution_requests: HashMap<PayloadId, ExecutionRequests<E>>,
|
||||
/// If set, the next call to `build_new_execution_payload` will associate these
|
||||
/// execution requests with the generated payload ID.
|
||||
next_execution_requests: Option<ExecutionRequests<E>>,
|
||||
}
|
||||
|
||||
fn make_rng() -> Arc<Mutex<StdRng>> {
|
||||
@@ -172,9 +181,6 @@ fn make_rng() -> Arc<Mutex<StdRng>> {
|
||||
impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
terminal_total_difficulty: Uint256,
|
||||
terminal_block_number: u64,
|
||||
terminal_block_hash: ExecutionBlockHash,
|
||||
shanghai_time: Option<u64>,
|
||||
cancun_time: Option<u64>,
|
||||
prague_time: Option<u64>,
|
||||
@@ -188,9 +194,9 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
finalized_block_hash: <_>::default(),
|
||||
blocks: <_>::default(),
|
||||
block_hashes: <_>::default(),
|
||||
terminal_total_difficulty,
|
||||
terminal_block_number,
|
||||
terminal_block_hash,
|
||||
terminal_total_difficulty: Default::default(),
|
||||
terminal_block_number: 0,
|
||||
terminal_block_hash: Default::default(),
|
||||
pending_payloads: <_>::default(),
|
||||
next_payload_id: 0,
|
||||
payload_ids: <_>::default(),
|
||||
@@ -204,6 +210,8 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
blobs_bundles: <_>::default(),
|
||||
kzg,
|
||||
rng: make_rng(),
|
||||
execution_requests: <_>::default(),
|
||||
next_execution_requests: None,
|
||||
};
|
||||
|
||||
generator.insert_pow_block(0).unwrap();
|
||||
@@ -296,25 +304,6 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
.and_then(|block| block.as_execution_payload())
|
||||
}
|
||||
|
||||
pub fn move_to_block_prior_to_terminal_block(&mut self) -> Result<(), String> {
|
||||
let target_block = self
|
||||
.terminal_block_number
|
||||
.checked_sub(1)
|
||||
.ok_or("terminal pow block is 0")?;
|
||||
self.move_to_pow_block(target_block)
|
||||
}
|
||||
|
||||
pub fn move_to_terminal_block(&mut self) -> Result<(), String> {
|
||||
self.move_to_pow_block(self.terminal_block_number)
|
||||
}
|
||||
|
||||
pub fn move_to_pow_block(&mut self, target_block: u64) -> Result<(), String> {
|
||||
let next_block = self.latest_block().unwrap().block_number() + 1;
|
||||
assert!(target_block >= next_block);
|
||||
|
||||
self.insert_pow_blocks(next_block..=target_block)
|
||||
}
|
||||
|
||||
pub fn drop_all_blocks(&mut self) {
|
||||
self.blocks = <_>::default();
|
||||
self.block_hashes = <_>::default();
|
||||
@@ -483,6 +472,49 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
self.blobs_bundles.get(id).cloned()
|
||||
}
|
||||
|
||||
pub fn get_execution_requests(&self, id: &PayloadId) -> Option<ExecutionRequests<E>> {
|
||||
self.execution_requests.get(id).cloned()
|
||||
}
|
||||
|
||||
/// Set execution requests to be returned alongside the next generated payload.
|
||||
pub fn set_next_execution_requests(&mut self, requests: ExecutionRequests<E>) {
|
||||
self.next_execution_requests = Some(requests);
|
||||
}
|
||||
|
||||
/// Look up a blob and proof by versioned hash across all stored bundles.
|
||||
pub fn get_blob_and_proof(&self, versioned_hash: &Hash256) -> Option<BlobAndProof<E>> {
|
||||
self.blobs_bundles
|
||||
.iter()
|
||||
.find_map(|(payload_id, blobs_bundle)| {
|
||||
let (blob_idx, _) =
|
||||
blobs_bundle
|
||||
.commitments
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, commitment)| {
|
||||
&kzg_commitment_to_versioned_hash(commitment) == versioned_hash
|
||||
})?;
|
||||
let is_fulu = self.payload_ids.get(payload_id)?.fork_name().fulu_enabled();
|
||||
let blob = blobs_bundle.blobs.get(blob_idx)?.clone();
|
||||
if is_fulu {
|
||||
let start = blob_idx * E::cells_per_ext_blob();
|
||||
let end = start + E::cells_per_ext_blob();
|
||||
let proofs = blobs_bundle
|
||||
.proofs
|
||||
.get(start..end)?
|
||||
.to_vec()
|
||||
.try_into()
|
||||
.ok()?;
|
||||
Some(BlobAndProof::V2(BlobAndProofV2 { blob, proofs }))
|
||||
} else {
|
||||
Some(BlobAndProof::V1(BlobAndProofV1 {
|
||||
blob,
|
||||
proof: *blobs_bundle.proofs.get(blob_idx)?,
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new_payload(&mut self, payload: ExecutionPayload<E>) -> PayloadStatusV1 {
|
||||
let Some(parent) = self.blocks.get(&payload.parent_hash()) else {
|
||||
return PayloadStatusV1 {
|
||||
@@ -541,6 +573,21 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
.contains_key(&forkchoice_state.finalized_block_hash);
|
||||
|
||||
if unknown_head_block_hash || unknown_safe_block_hash || unknown_finalized_block_hash {
|
||||
if unknown_head_block_hash {
|
||||
warn!(?head_block_hash, "Received unknown head block hash");
|
||||
}
|
||||
if unknown_safe_block_hash {
|
||||
warn!(
|
||||
safe_block_hash = ?forkchoice_state.safe_block_hash,
|
||||
"Received unknown safe block hash"
|
||||
);
|
||||
}
|
||||
if unknown_finalized_block_hash {
|
||||
warn!(
|
||||
finalized_block_hash = ?forkchoice_state.finalized_block_hash,
|
||||
"Received unknown finalized block hash"
|
||||
)
|
||||
}
|
||||
return Ok(JsonForkchoiceUpdatedV1Response {
|
||||
payload_status: JsonPayloadStatusV1 {
|
||||
status: JsonPayloadStatusV1Status::Syncing,
|
||||
@@ -730,6 +777,9 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
blob_gas_used: 0,
|
||||
excess_blob_gas: 0,
|
||||
}),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
PayloadAttributes::V4(pa) => match self.get_fork_at_timestamp(pa.timestamp) {
|
||||
ForkName::Gloas => ExecutionPayload::Gloas(ExecutionPayloadGloas {
|
||||
parent_hash: head_block_hash,
|
||||
fee_recipient: pa.suggested_fee_recipient,
|
||||
@@ -748,11 +798,18 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
withdrawals: pa.withdrawals.clone().try_into().unwrap(),
|
||||
blob_gas_used: 0,
|
||||
excess_blob_gas: 0,
|
||||
block_access_list: VariableList::empty(),
|
||||
slot_number: pa.slot_number.into(),
|
||||
}),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
};
|
||||
|
||||
// Store execution requests for this payload if configured.
|
||||
if let Some(requests) = self.next_execution_requests.take() {
|
||||
self.execution_requests.insert(id, requests);
|
||||
}
|
||||
|
||||
let fork_name = execution_payload.fork_name();
|
||||
if fork_name.deneb_enabled() {
|
||||
// get random number between 0 and 1 blobs by default
|
||||
@@ -886,27 +943,22 @@ fn payload_id_from_u64(n: u64) -> PayloadId {
|
||||
n.to_le_bytes()
|
||||
}
|
||||
|
||||
pub fn generate_genesis_header<E: EthSpec>(
|
||||
spec: &ChainSpec,
|
||||
post_transition_merge: bool,
|
||||
) -> Option<ExecutionPayloadHeader<E>> {
|
||||
pub fn generate_genesis_header<E: EthSpec>(spec: &ChainSpec) -> Option<ExecutionPayloadHeader<E>> {
|
||||
let genesis_fork = spec.fork_name_at_slot::<E>(spec.genesis_slot);
|
||||
let genesis_block_hash =
|
||||
generate_genesis_block(spec.terminal_total_difficulty, DEFAULT_TERMINAL_BLOCK)
|
||||
.ok()
|
||||
.map(|block| block.block_hash);
|
||||
let genesis_block_hash = generate_genesis_block(Default::default(), 0)
|
||||
.ok()
|
||||
.map(|block| block.block_hash);
|
||||
let empty_transactions_root = Transactions::<E>::empty().tree_hash_root();
|
||||
match genesis_fork {
|
||||
ForkName::Base | ForkName::Altair => None,
|
||||
ForkName::Base | ForkName::Altair => {
|
||||
// Pre-Bellatrix forks have no execution payload
|
||||
None
|
||||
}
|
||||
ForkName::Bellatrix => {
|
||||
if post_transition_merge {
|
||||
let mut header = ExecutionPayloadHeader::Bellatrix(<_>::default());
|
||||
*header.block_hash_mut() = genesis_block_hash.unwrap_or_default();
|
||||
*header.transactions_root_mut() = empty_transactions_root;
|
||||
Some(header)
|
||||
} else {
|
||||
Some(ExecutionPayloadHeader::<E>::Bellatrix(<_>::default()))
|
||||
}
|
||||
let mut header = ExecutionPayloadHeader::Bellatrix(<_>::default());
|
||||
*header.block_hash_mut() = genesis_block_hash.unwrap_or_default();
|
||||
*header.transactions_root_mut() = empty_transactions_root;
|
||||
Some(header)
|
||||
}
|
||||
ForkName::Capella => {
|
||||
let mut header = ExecutionPayloadHeader::Capella(<_>::default());
|
||||
@@ -938,8 +990,14 @@ pub fn generate_genesis_header<E: EthSpec>(
|
||||
*header.transactions_root_mut() = empty_transactions_root;
|
||||
Some(header)
|
||||
}
|
||||
// TODO(EIP-7732): need to look into this
|
||||
ForkName::Gloas => None,
|
||||
ForkName::Gloas => {
|
||||
// TODO(gloas): we are using a Fulu header for now, but this gets fixed up by the
|
||||
// genesis builder anyway which translates it to bid/latest_block_hash.
|
||||
let mut header = ExecutionPayloadHeader::Fulu(<_>::default());
|
||||
*header.block_hash_mut() = genesis_block_hash.unwrap_or_default();
|
||||
*header.transactions_root_mut() = empty_transactions_root;
|
||||
Some(header)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -995,7 +1053,7 @@ pub fn generate_pow_block(
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use kzg::{Bytes48, CellRef, KzgBlobRef, trusted_setup::get_trusted_setup};
|
||||
use kzg::{CellRef, KzgBlobRef, trusted_setup::get_trusted_setup};
|
||||
use types::{MainnetEthSpec, MinimalEthSpec};
|
||||
|
||||
#[test]
|
||||
@@ -1086,10 +1144,11 @@ mod test {
|
||||
fn validate_blob_bundle_v1<E: EthSpec>() -> Result<(), String> {
|
||||
let kzg = load_kzg()?;
|
||||
let (kzg_commitment, kzg_proof, blob) = load_test_blobs_bundle_v1::<E>()?;
|
||||
let kzg_blob = kzg::Blob::from_bytes(blob.as_ref())
|
||||
.map(Box::new)
|
||||
.map_err(|e| format!("Error converting blob to kzg blob: {e:?}"))?;
|
||||
kzg.verify_blob_kzg_proof(&kzg_blob, kzg_commitment, kzg_proof)
|
||||
let kzg_blob: KzgBlobRef = blob
|
||||
.as_ref()
|
||||
.try_into()
|
||||
.map_err(|e| format!("Error converting blob to kzg blob ref: {e:?}"))?;
|
||||
kzg.verify_blob_kzg_proof(kzg_blob, kzg_commitment, kzg_proof)
|
||||
.map_err(|e| format!("Invalid blobs bundle: {e:?}"))
|
||||
}
|
||||
|
||||
@@ -1099,8 +1158,8 @@ mod test {
|
||||
load_test_blobs_bundle_v2::<E>().map(|(commitment, proofs, blob)| {
|
||||
let kzg_blob: KzgBlobRef = blob.as_ref().try_into().unwrap();
|
||||
(
|
||||
vec![Bytes48::from(commitment); proofs.len()],
|
||||
proofs.into_iter().map(|p| p.into()).collect::<Vec<_>>(),
|
||||
vec![commitment.0; proofs.len()],
|
||||
proofs.into_iter().map(|p| p.0).collect::<Vec<_>>(),
|
||||
kzg.compute_cells(kzg_blob).unwrap(),
|
||||
)
|
||||
})?;
|
||||
|
||||
@@ -5,6 +5,7 @@ use crate::test_utils::{DEFAULT_CLIENT_VERSION, DEFAULT_MOCK_EL_PAYLOAD_VALUE_WE
|
||||
use serde::{Deserialize, de::DeserializeOwned};
|
||||
use serde_json::Value as JsonValue;
|
||||
use std::sync::Arc;
|
||||
use tracing::debug;
|
||||
use types::Transaction;
|
||||
|
||||
pub const GENERIC_ERROR_CODE: i64 = -1234;
|
||||
@@ -29,6 +30,8 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
.ok_or_else(|| "missing/invalid params field".to_string())
|
||||
.map_err(|s| (s, GENERIC_ERROR_CODE))?;
|
||||
|
||||
debug!(method, "Mock execution engine");
|
||||
|
||||
match method {
|
||||
ETH_SYNCING => ctx
|
||||
.syncing_response
|
||||
@@ -100,7 +103,8 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
ENGINE_NEW_PAYLOAD_V1
|
||||
| ENGINE_NEW_PAYLOAD_V2
|
||||
| ENGINE_NEW_PAYLOAD_V3
|
||||
| ENGINE_NEW_PAYLOAD_V4 => {
|
||||
| ENGINE_NEW_PAYLOAD_V4
|
||||
| ENGINE_NEW_PAYLOAD_V5 => {
|
||||
let request = match method {
|
||||
ENGINE_NEW_PAYLOAD_V1 => JsonExecutionPayload::Bellatrix(
|
||||
get_param::<JsonExecutionPayloadBellatrix<E>>(params, 0)
|
||||
@@ -116,21 +120,16 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
ENGINE_NEW_PAYLOAD_V3 => get_param::<JsonExecutionPayloadDeneb<E>>(params, 0)
|
||||
.map(|jep| JsonExecutionPayload::Deneb(jep))
|
||||
.map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?,
|
||||
ENGINE_NEW_PAYLOAD_V4 => get_param::<JsonExecutionPayloadGloas<E>>(params, 0)
|
||||
.map(|jep| JsonExecutionPayload::Gloas(jep))
|
||||
.or_else(|_| {
|
||||
get_param::<JsonExecutionPayloadFulu<E>>(params, 0)
|
||||
.map(|jep| JsonExecutionPayload::Fulu(jep))
|
||||
})
|
||||
ENGINE_NEW_PAYLOAD_V4 => get_param::<JsonExecutionPayloadFulu<E>>(params, 0)
|
||||
.map(|jep| JsonExecutionPayload::Fulu(jep))
|
||||
.or_else(|_| {
|
||||
get_param::<JsonExecutionPayloadElectra<E>>(params, 0)
|
||||
.map(|jep| JsonExecutionPayload::Electra(jep))
|
||||
})
|
||||
.map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?,
|
||||
// TODO(EIP7805) fix
|
||||
// ENGINE_NEW_PAYLOAD_V5 => get_param::<JsonExecutionPayloadV5<E>>(params, 0)
|
||||
// .map(|jep| JsonExecutionPayload::V5(jep))
|
||||
// .map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?,
|
||||
ENGINE_NEW_PAYLOAD_V5 => get_param::<JsonExecutionPayloadGloas<E>>(params, 0)
|
||||
.map(|jep| JsonExecutionPayload::Gloas(jep))
|
||||
.map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
@@ -232,6 +231,14 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
));
|
||||
}
|
||||
}
|
||||
ForkName::Gloas => {
|
||||
if method != ENGINE_NEW_PAYLOAD_V5 {
|
||||
return Err((
|
||||
format!("{} called after Gloas fork!", method),
|
||||
GENERIC_ERROR_CODE,
|
||||
));
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
@@ -270,8 +277,9 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
ENGINE_GET_PAYLOAD_V1
|
||||
| ENGINE_GET_PAYLOAD_V2
|
||||
| ENGINE_GET_PAYLOAD_V3
|
||||
| ENGINE_GET_PAYLOAD_V4
|
||||
| ENGINE_GET_PAYLOAD_V5
|
||||
| ENGINE_GET_PAYLOAD_V4 => {
|
||||
| ENGINE_GET_PAYLOAD_V6 => {
|
||||
let request: JsonPayloadIdRequest =
|
||||
get_param(params, 0).map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?;
|
||||
let id = request.into();
|
||||
@@ -288,6 +296,10 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
})?;
|
||||
|
||||
let maybe_blobs = ctx.execution_block_generator.write().get_blobs_bundle(&id);
|
||||
let maybe_execution_requests = ctx
|
||||
.execution_block_generator
|
||||
.read()
|
||||
.get_execution_requests(&id);
|
||||
|
||||
// validate method called correctly according to shanghai fork time
|
||||
if ctx
|
||||
@@ -356,7 +368,8 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
&& (method == ENGINE_GET_PAYLOAD_V1
|
||||
|| method == ENGINE_GET_PAYLOAD_V2
|
||||
|| method == ENGINE_GET_PAYLOAD_V3
|
||||
|| method == ENGINE_GET_PAYLOAD_V4)
|
||||
|| method == ENGINE_GET_PAYLOAD_V4
|
||||
|| method == ENGINE_GET_PAYLOAD_V5)
|
||||
{
|
||||
return Err((
|
||||
format!("{} called after Gloas fork!", method),
|
||||
@@ -423,8 +436,10 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
))?
|
||||
.into(),
|
||||
should_override_builder: false,
|
||||
// TODO(electra): add EL requests in mock el
|
||||
execution_requests: Default::default(),
|
||||
execution_requests: maybe_execution_requests
|
||||
.clone()
|
||||
.unwrap_or_default()
|
||||
.into(),
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
@@ -444,7 +459,10 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
))?
|
||||
.into(),
|
||||
should_override_builder: false,
|
||||
execution_requests: Default::default(),
|
||||
execution_requests: maybe_execution_requests
|
||||
.clone()
|
||||
.unwrap_or_default()
|
||||
.into(),
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
@@ -463,18 +481,25 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
})
|
||||
}
|
||||
ENGINE_GET_PAYLOAD_V6 => {
|
||||
Ok(match JsonExecutionPayload::try_from(response).unwrap() {
|
||||
JsonExecutionPayload::Gloas(execution_payload) => {
|
||||
serde_json::to_value(JsonGetPayloadResponseGloas {
|
||||
execution_payload,
|
||||
block_value: Uint256::from(DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI),
|
||||
blobs_bundle: maybe_blobs
|
||||
.ok_or((
|
||||
"No blobs returned despite V5 Payload".to_string(),
|
||||
"No blobs returned despite V6 Payload".to_string(),
|
||||
GENERIC_ERROR_CODE,
|
||||
))?
|
||||
.into(),
|
||||
should_override_builder: false,
|
||||
execution_requests: Default::default(),
|
||||
execution_requests: maybe_execution_requests
|
||||
.unwrap_or_default()
|
||||
.into(),
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
@@ -484,9 +509,39 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
ENGINE_GET_BLOBS_V1 => {
|
||||
let versioned_hashes =
|
||||
get_param::<Vec<Hash256>>(params, 0).map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?;
|
||||
let generator = ctx.execution_block_generator.read();
|
||||
// V1: per-element nullable array, positionally matching the request.
|
||||
let response: Vec<Option<BlobAndProofV1<E>>> = versioned_hashes
|
||||
.iter()
|
||||
.map(|hash| match generator.get_blob_and_proof(hash) {
|
||||
Some(BlobAndProof::V1(v1)) => Some(v1),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
Ok(serde_json::to_value(response).unwrap())
|
||||
}
|
||||
ENGINE_GET_BLOBS_V2 => {
|
||||
let versioned_hashes =
|
||||
get_param::<Vec<Hash256>>(params, 0).map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?;
|
||||
let generator = ctx.execution_block_generator.read();
|
||||
// V2: all-or-nothing — null if any blob is missing.
|
||||
let results: Vec<Option<BlobAndProofV2<E>>> = versioned_hashes
|
||||
.iter()
|
||||
.map(|hash| match generator.get_blob_and_proof(hash) {
|
||||
Some(BlobAndProof::V2(v2)) => Some(v2),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
let response: Option<Vec<BlobAndProofV2<E>>> = results.into_iter().collect();
|
||||
Ok(serde_json::to_value(response).unwrap())
|
||||
}
|
||||
ENGINE_FORKCHOICE_UPDATED_V1
|
||||
| ENGINE_FORKCHOICE_UPDATED_V2
|
||||
| ENGINE_FORKCHOICE_UPDATED_V3 => {
|
||||
| ENGINE_FORKCHOICE_UPDATED_V3
|
||||
| ENGINE_FORKCHOICE_UPDATED_V4 => {
|
||||
let forkchoice_state: JsonForkchoiceStateV1 =
|
||||
get_param(params, 0).map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?;
|
||||
let payload_attributes = match method {
|
||||
@@ -533,9 +588,20 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
.map(|opt| opt.map(JsonPayloadAttributes::V3))
|
||||
.map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?
|
||||
}
|
||||
ENGINE_FORKCHOICE_UPDATED_V4 => {
|
||||
get_param::<Option<JsonPayloadAttributesV4>>(params, 1)
|
||||
.map(|opt| opt.map(JsonPayloadAttributes::V4))
|
||||
.map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
debug!(
|
||||
?payload_attributes,
|
||||
?forkchoice_state,
|
||||
"ENGINE_FORKCHOICE_UPDATED"
|
||||
);
|
||||
|
||||
// validate method called correctly according to fork time
|
||||
if let Some(pa) = payload_attributes.as_ref() {
|
||||
match ctx
|
||||
@@ -598,6 +664,14 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
));
|
||||
}
|
||||
}
|
||||
ForkName::Gloas => {
|
||||
if method != ENGINE_FORKCHOICE_UPDATED_V4 {
|
||||
return Err((
|
||||
format!("{} called after Gloas fork! Use V4.", method),
|
||||
FORK_REQUEST_MISMATCH_ERROR_CODE,
|
||||
));
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ use tokio_stream::StreamExt;
|
||||
use tracing::{debug, error, info, warn};
|
||||
use tree_hash::TreeHash;
|
||||
use types::ExecutionBlockHash;
|
||||
use types::builder_bid::{
|
||||
use types::builder::{
|
||||
BuilderBid, BuilderBidBellatrix, BuilderBidCapella, BuilderBidDeneb, BuilderBidEip7805,
|
||||
BuilderBidElectra, BuilderBidFulu, SignedBuilderBid,
|
||||
};
|
||||
@@ -266,7 +266,7 @@ impl<E: EthSpec> BidStuff<E> for BuilderBid<E> {
|
||||
}
|
||||
|
||||
fn sign_builder_message(&mut self, sk: &SecretKey, spec: &ChainSpec) -> Signature {
|
||||
let domain = spec.get_builder_domain();
|
||||
let domain = spec.get_builder_application_domain();
|
||||
let message = self.signing_root(domain);
|
||||
sk.sign(message)
|
||||
}
|
||||
@@ -840,6 +840,10 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
|
||||
let head_block_root = head_block_root.unwrap_or(head.canonical_root());
|
||||
|
||||
// TODO(gloas): Currently the tests are pre-Gloas and we are not considering
|
||||
// other payload statuses. This codepath may not be relevant for Gloas.
|
||||
let head_payload_status = fork_choice::PayloadStatus::Pending;
|
||||
|
||||
let head_execution_payload = head
|
||||
.message()
|
||||
.body()
|
||||
@@ -900,7 +904,8 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
.data
|
||||
.genesis_time
|
||||
};
|
||||
let timestamp = (slots_since_genesis * self.spec.seconds_per_slot) + genesis_time;
|
||||
let timestamp =
|
||||
(slots_since_genesis * self.spec.get_slot_duration().as_secs()) + genesis_time;
|
||||
|
||||
let head_state: BeaconState<E> = self
|
||||
.beacon_client
|
||||
@@ -937,17 +942,25 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
fee_recipient,
|
||||
expected_withdrawals,
|
||||
None,
|
||||
None,
|
||||
),
|
||||
ForkName::Deneb
|
||||
| ForkName::Electra
|
||||
| ForkName::Fulu
|
||||
| ForkName::Eip7805
|
||||
| ForkName::Gloas => PayloadAttributes::new(
|
||||
ForkName::Deneb | ForkName::Electra | ForkName::Fulu | ForkName::Eip7805 => {
|
||||
PayloadAttributes::new(
|
||||
timestamp,
|
||||
*prev_randao,
|
||||
fee_recipient,
|
||||
expected_withdrawals,
|
||||
Some(head_block_root),
|
||||
None,
|
||||
)
|
||||
}
|
||||
ForkName::Gloas => PayloadAttributes::new(
|
||||
timestamp,
|
||||
*prev_randao,
|
||||
fee_recipient,
|
||||
expected_withdrawals,
|
||||
Some(head_block_root),
|
||||
Some(slot.as_u64()),
|
||||
),
|
||||
ForkName::Base | ForkName::Altair => {
|
||||
return Err("invalid fork".to_string());
|
||||
@@ -967,7 +980,13 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
);
|
||||
|
||||
self.el
|
||||
.insert_proposer(slot, head_block_root, val_index, payload_attributes.clone())
|
||||
.insert_proposer(
|
||||
slot,
|
||||
head_block_root,
|
||||
head_payload_status,
|
||||
val_index,
|
||||
payload_attributes.clone(),
|
||||
)
|
||||
.await;
|
||||
|
||||
let forkchoice_update_params = ForkchoiceUpdateParameters {
|
||||
@@ -985,6 +1004,7 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
finalized_execution_hash,
|
||||
slot - 1,
|
||||
head_block_root,
|
||||
head_payload_status,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| format!("fcu call failed : {:?}", e))?;
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
use crate::{
|
||||
test_utils::{
|
||||
DEFAULT_JWT_SECRET, DEFAULT_TERMINAL_BLOCK, DEFAULT_TERMINAL_DIFFICULTY, MockServer,
|
||||
},
|
||||
*,
|
||||
};
|
||||
use crate::{test_utils::DEFAULT_JWT_SECRET, test_utils::MockServer, *};
|
||||
use alloy_primitives::B256 as H256;
|
||||
use fixed_bytes::FixedBytesExtended;
|
||||
use kzg::Kzg;
|
||||
@@ -20,12 +15,10 @@ pub struct MockExecutionLayer<E: EthSpec> {
|
||||
impl<E: EthSpec> MockExecutionLayer<E> {
|
||||
pub fn default_params(executor: TaskExecutor) -> Self {
|
||||
let mut spec = MainnetEthSpec::default_spec();
|
||||
spec.terminal_total_difficulty = Uint256::from(DEFAULT_TERMINAL_DIFFICULTY);
|
||||
spec.terminal_block_hash = ExecutionBlockHash::zero();
|
||||
spec.terminal_block_hash_activation_epoch = Epoch::new(0);
|
||||
Self::new(
|
||||
executor,
|
||||
DEFAULT_TERMINAL_BLOCK,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
@@ -41,7 +34,6 @@ impl<E: EthSpec> MockExecutionLayer<E> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
executor: TaskExecutor,
|
||||
terminal_block: u64,
|
||||
shanghai_time: Option<u64>,
|
||||
cancun_time: Option<u64>,
|
||||
prague_time: Option<u64>,
|
||||
@@ -58,9 +50,6 @@ impl<E: EthSpec> MockExecutionLayer<E> {
|
||||
let server = MockServer::new(
|
||||
&handle,
|
||||
jwt_key,
|
||||
spec.terminal_total_difficulty,
|
||||
terminal_block,
|
||||
spec.terminal_block_hash,
|
||||
shanghai_time,
|
||||
cancun_time,
|
||||
prague_time,
|
||||
@@ -104,20 +93,34 @@ impl<E: EthSpec> MockExecutionLayer<E> {
|
||||
let timestamp = block_number;
|
||||
let prev_randao = Hash256::from_low_u64_be(block_number);
|
||||
let head_block_root = Hash256::repeat_byte(42);
|
||||
// TODO(gloas): allow statuses other than Pending?
|
||||
let head_payload_status = fork_choice::PayloadStatus::Pending;
|
||||
let forkchoice_update_params = ForkchoiceUpdateParameters {
|
||||
head_root: head_block_root,
|
||||
head_hash: Some(parent_hash),
|
||||
justified_hash: None,
|
||||
finalized_hash: None,
|
||||
};
|
||||
let payload_attributes =
|
||||
PayloadAttributes::new(timestamp, prev_randao, Address::repeat_byte(42), None, None);
|
||||
let payload_attributes = PayloadAttributes::new(
|
||||
timestamp,
|
||||
prev_randao,
|
||||
Address::repeat_byte(42),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
// Insert a proposer to ensure the fork choice updated command works.
|
||||
let slot = Slot::new(0);
|
||||
let validator_index = 0;
|
||||
self.el
|
||||
.insert_proposer(slot, head_block_root, validator_index, payload_attributes)
|
||||
.insert_proposer(
|
||||
slot,
|
||||
head_block_root,
|
||||
head_payload_status,
|
||||
validator_index,
|
||||
payload_attributes,
|
||||
)
|
||||
.await;
|
||||
|
||||
self.el
|
||||
@@ -127,6 +130,7 @@ impl<E: EthSpec> MockExecutionLayer<E> {
|
||||
ExecutionBlockHash::zero(),
|
||||
slot,
|
||||
head_block_root,
|
||||
head_payload_status,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
@@ -138,8 +142,14 @@ impl<E: EthSpec> MockExecutionLayer<E> {
|
||||
chain_health: ChainHealth::Healthy,
|
||||
};
|
||||
let suggested_fee_recipient = self.el.get_suggested_fee_recipient(validator_index).await;
|
||||
let payload_attributes =
|
||||
PayloadAttributes::new(timestamp, prev_randao, suggested_fee_recipient, None, None);
|
||||
let payload_attributes = PayloadAttributes::new(
|
||||
timestamp,
|
||||
prev_randao,
|
||||
suggested_fee_recipient,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
let payload_parameters = PayloadParameters {
|
||||
parent_hash,
|
||||
@@ -185,8 +195,14 @@ impl<E: EthSpec> MockExecutionLayer<E> {
|
||||
chain_health: ChainHealth::Healthy,
|
||||
};
|
||||
let suggested_fee_recipient = self.el.get_suggested_fee_recipient(validator_index).await;
|
||||
let payload_attributes =
|
||||
PayloadAttributes::new(timestamp, prev_randao, suggested_fee_recipient, None, None);
|
||||
let payload_attributes = PayloadAttributes::new(
|
||||
timestamp,
|
||||
prev_randao,
|
||||
suggested_fee_recipient,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
let payload_parameters = PayloadParameters {
|
||||
parent_hash,
|
||||
@@ -276,6 +292,7 @@ impl<E: EthSpec> MockExecutionLayer<E> {
|
||||
// Use junk values for slot/head-root to ensure there is no payload supplied.
|
||||
let slot = Slot::new(0);
|
||||
let head_block_root = Hash256::repeat_byte(13);
|
||||
// TODO(gloas): reconsider the state_payload_status
|
||||
self.el
|
||||
.notify_forkchoice_updated(
|
||||
block_hash,
|
||||
@@ -283,6 +300,7 @@ impl<E: EthSpec> MockExecutionLayer<E> {
|
||||
ExecutionBlockHash::zero(),
|
||||
slot,
|
||||
head_block_root,
|
||||
fork_choice::PayloadStatus::Pending,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
@@ -296,53 +314,4 @@ impl<E: EthSpec> MockExecutionLayer<E> {
|
||||
assert_eq!(head_execution_block.block_hash(), block_hash);
|
||||
assert_eq!(head_execution_block.parent_hash(), parent_hash);
|
||||
}
|
||||
|
||||
pub fn move_to_block_prior_to_terminal_block(self) -> Self {
|
||||
self.server
|
||||
.execution_block_generator()
|
||||
.move_to_block_prior_to_terminal_block()
|
||||
.unwrap();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn move_to_terminal_block(self) -> Self {
|
||||
self.server
|
||||
.execution_block_generator()
|
||||
.move_to_terminal_block()
|
||||
.unwrap();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn produce_forked_pow_block(self) -> (Self, ExecutionBlockHash) {
|
||||
let head_block = self
|
||||
.server
|
||||
.execution_block_generator()
|
||||
.latest_block()
|
||||
.unwrap();
|
||||
|
||||
let block_hash = self
|
||||
.server
|
||||
.execution_block_generator()
|
||||
.insert_pow_block_by_hash(head_block.parent_hash(), 1)
|
||||
.unwrap();
|
||||
(self, block_hash)
|
||||
}
|
||||
|
||||
pub async fn with_terminal_block<U, V>(self, func: U) -> Self
|
||||
where
|
||||
U: Fn(Arc<ChainSpec>, ExecutionLayer<E>, Option<ExecutionBlock>) -> V,
|
||||
V: Future<Output = ()>,
|
||||
{
|
||||
let terminal_block_number = self
|
||||
.server
|
||||
.execution_block_generator()
|
||||
.terminal_block_number;
|
||||
let terminal_block = self
|
||||
.server
|
||||
.execution_block_generator()
|
||||
.execution_block_by_number(terminal_block_number);
|
||||
|
||||
func(self.spec.clone(), self.el.clone(), terminal_block).await;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,8 +35,6 @@ pub use hook::Hook;
|
||||
pub use mock_builder::{MockBuilder, Operation, mock_builder_extra_data};
|
||||
pub use mock_execution_layer::MockExecutionLayer;
|
||||
|
||||
pub const DEFAULT_TERMINAL_DIFFICULTY: u64 = 6400;
|
||||
pub const DEFAULT_TERMINAL_BLOCK: u64 = 64;
|
||||
pub const DEFAULT_JWT_SECRET: [u8; 32] = [42; 32];
|
||||
pub const DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI: u128 = 10_000_000_000_000_000;
|
||||
pub const DEFAULT_BUILDER_PAYLOAD_VALUE_WEI: u128 = 20_000_000_000_000_000;
|
||||
@@ -45,9 +43,11 @@ pub const DEFAULT_ENGINE_CAPABILITIES: EngineCapabilities = EngineCapabilities {
|
||||
new_payload_v2: true,
|
||||
new_payload_v3: true,
|
||||
new_payload_v4: true,
|
||||
new_payload_v5: true,
|
||||
forkchoice_updated_v1: true,
|
||||
forkchoice_updated_v2: true,
|
||||
forkchoice_updated_v3: true,
|
||||
forkchoice_updated_v4: true,
|
||||
get_payload_bodies_by_hash_v1: true,
|
||||
get_payload_bodies_by_range_v1: true,
|
||||
get_payload_v1: true,
|
||||
@@ -55,10 +55,12 @@ pub const DEFAULT_ENGINE_CAPABILITIES: EngineCapabilities = EngineCapabilities {
|
||||
get_payload_v3: true,
|
||||
get_payload_v4: true,
|
||||
get_payload_v5: true,
|
||||
get_payload_v6: true,
|
||||
get_client_version_v1: true,
|
||||
get_blobs_v1: true,
|
||||
get_blobs_v2: true,
|
||||
get_inclusion_list_v1: true,
|
||||
get_blobs_v3: true,
|
||||
};
|
||||
|
||||
pub static DEFAULT_CLIENT_VERSION: LazyLock<JsonClientVersionV1> =
|
||||
@@ -80,9 +82,6 @@ mod mock_execution_layer;
|
||||
pub struct MockExecutionConfig {
|
||||
pub server_config: Config,
|
||||
pub jwt_key: JwtKey,
|
||||
pub terminal_difficulty: Uint256,
|
||||
pub terminal_block: u64,
|
||||
pub terminal_block_hash: ExecutionBlockHash,
|
||||
pub shanghai_time: Option<u64>,
|
||||
pub cancun_time: Option<u64>,
|
||||
pub prague_time: Option<u64>,
|
||||
@@ -95,9 +94,6 @@ impl Default for MockExecutionConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
jwt_key: JwtKey::random(),
|
||||
terminal_difficulty: Uint256::from(DEFAULT_TERMINAL_DIFFICULTY),
|
||||
terminal_block: DEFAULT_TERMINAL_BLOCK,
|
||||
terminal_block_hash: ExecutionBlockHash::zero(),
|
||||
server_config: Config::default(),
|
||||
shanghai_time: None,
|
||||
cancun_time: None,
|
||||
@@ -121,9 +117,6 @@ impl<E: EthSpec> MockServer<E> {
|
||||
Self::new(
|
||||
&runtime::Handle::current(),
|
||||
JwtKey::from_slice(&DEFAULT_JWT_SECRET).unwrap(),
|
||||
Uint256::from(DEFAULT_TERMINAL_DIFFICULTY),
|
||||
DEFAULT_TERMINAL_BLOCK,
|
||||
ExecutionBlockHash::zero(),
|
||||
None, // FIXME(capella): should this be the default?
|
||||
None, // FIXME(deneb): should this be the default?
|
||||
None, // FIXME(electra): should this be the default?
|
||||
@@ -142,9 +135,6 @@ impl<E: EthSpec> MockServer<E> {
|
||||
create_test_tracing_subscriber();
|
||||
let MockExecutionConfig {
|
||||
jwt_key,
|
||||
terminal_difficulty,
|
||||
terminal_block,
|
||||
terminal_block_hash,
|
||||
server_config,
|
||||
shanghai_time,
|
||||
cancun_time,
|
||||
@@ -156,9 +146,6 @@ impl<E: EthSpec> MockServer<E> {
|
||||
let last_echo_request = Arc::new(RwLock::new(None));
|
||||
let preloaded_responses = Arc::new(Mutex::new(vec![]));
|
||||
let execution_block_generator = ExecutionBlockGenerator::new(
|
||||
terminal_difficulty,
|
||||
terminal_block,
|
||||
terminal_block_hash,
|
||||
shanghai_time,
|
||||
cancun_time,
|
||||
prague_time,
|
||||
@@ -221,9 +208,6 @@ impl<E: EthSpec> MockServer<E> {
|
||||
pub fn new(
|
||||
handle: &runtime::Handle,
|
||||
jwt_key: JwtKey,
|
||||
terminal_difficulty: Uint256,
|
||||
terminal_block: u64,
|
||||
terminal_block_hash: ExecutionBlockHash,
|
||||
shanghai_time: Option<u64>,
|
||||
cancun_time: Option<u64>,
|
||||
prague_time: Option<u64>,
|
||||
@@ -237,9 +221,6 @@ impl<E: EthSpec> MockServer<E> {
|
||||
MockExecutionConfig {
|
||||
server_config: Config::default(),
|
||||
jwt_key,
|
||||
terminal_difficulty,
|
||||
terminal_block,
|
||||
terminal_block_hash,
|
||||
shanghai_time,
|
||||
cancun_time,
|
||||
prague_time,
|
||||
@@ -762,7 +743,7 @@ pub fn serve<E: EthSpec>(
|
||||
|
||||
info!(
|
||||
listen_address = listening_socket.to_string(),
|
||||
"Metrics HTTP server started"
|
||||
"Mock execution client started"
|
||||
);
|
||||
|
||||
Ok((listening_socket, server))
|
||||
|
||||
Reference in New Issue
Block a user