Update Mock Builder for Post-Capella Tests (#3958)
* Update Mock Builder for Post-Capella Tests * Add _mut Suffix to BidStuff Functions * Fix Setting Gas Limit
This commit is contained in:
parent
39f8327f73
commit
e743d75c9b
19
Cargo.lock
generated
19
Cargo.lock
generated
@ -538,7 +538,7 @@ checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf"
|
||||
[[package]]
|
||||
name = "beacon-api-client"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/ralexstokes/beacon-api-client?rev=7d5d8dad1648f771573f42585ad8080a45b05689#7d5d8dad1648f771573f42585ad8080a45b05689"
|
||||
source = "git+https://github.com/ralexstokes/beacon-api-client#53690a711e33614d59d4d44fb09762b4699e2a4e"
|
||||
dependencies = [
|
||||
"ethereum-consensus",
|
||||
"http",
|
||||
@ -2342,7 +2342,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ethereum-consensus"
|
||||
version = "0.1.1"
|
||||
source = "git+https://github.com/ralexstokes/ethereum-consensus?rev=a8110af76d97bf2bf27fb987a671808fcbdf1834#a8110af76d97bf2bf27fb987a671808fcbdf1834"
|
||||
source = "git+https://github.com/ralexstokes//ethereum-consensus?rev=9b0ee0a8a45b968c8df5e7e64ea1c094e16f053d#9b0ee0a8a45b968c8df5e7e64ea1c094e16f053d"
|
||||
dependencies = [
|
||||
"async-stream",
|
||||
"blst",
|
||||
@ -2351,6 +2351,7 @@ dependencies = [
|
||||
"hex",
|
||||
"integer-sqrt",
|
||||
"multiaddr 0.14.0",
|
||||
"multihash",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -2508,7 +2509,7 @@ dependencies = [
|
||||
"lazy_static",
|
||||
"lighthouse_metrics",
|
||||
"lru 0.7.8",
|
||||
"mev-build-rs",
|
||||
"mev-rs",
|
||||
"parking_lot 0.12.1",
|
||||
"rand 0.8.5",
|
||||
"reqwest",
|
||||
@ -4678,18 +4679,19 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mev-build-rs"
|
||||
name = "mev-rs"
|
||||
version = "0.2.1"
|
||||
source = "git+https://github.com/ralexstokes/mev-rs?rev=6c99b0fbdc0427b1625469d2e575303ce08de5b8#6c99b0fbdc0427b1625469d2e575303ce08de5b8"
|
||||
source = "git+https://github.com/ralexstokes//mev-rs?rev=7813d4a4a564e0754e9aaab2d95520ba437c3889#7813d4a4a564e0754e9aaab2d95520ba437c3889"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum",
|
||||
"beacon-api-client",
|
||||
"ethereum-consensus",
|
||||
"hyper",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"ssz-rs",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
@ -7303,11 +7305,10 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ssz-rs"
|
||||
version = "0.8.0"
|
||||
source = "git+https://github.com/ralexstokes/ssz-rs?rev=cb08f1#cb08f18ca919cc1b685b861d0fa9e2daabe89737"
|
||||
source = "git+https://github.com/ralexstokes//ssz-rs?rev=adf1a0b14cef90b9536f28ef89da1fab316465e1#adf1a0b14cef90b9536f28ef89da1fab316465e1"
|
||||
dependencies = [
|
||||
"bitvec 1.0.1",
|
||||
"hex",
|
||||
"lazy_static",
|
||||
"num-bigint",
|
||||
"serde",
|
||||
"sha2 0.9.9",
|
||||
@ -7318,7 +7319,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ssz-rs-derive"
|
||||
version = "0.8.0"
|
||||
source = "git+https://github.com/ralexstokes/ssz-rs?rev=cb08f1#cb08f18ca919cc1b685b861d0fa9e2daabe89737"
|
||||
source = "git+https://github.com/ralexstokes//ssz-rs?rev=adf1a0b14cef90b9536f28ef89da1fab316465e1#adf1a0b14cef90b9536f28ef89da1fab316465e1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -103,6 +103,13 @@ tree_hash_derive = { path = "consensus/tree_hash_derive" }
|
||||
eth2_serde_utils = { path = "consensus/serde_utils" }
|
||||
arbitrary = { git = "https://github.com/michaelsproul/arbitrary", rev="a572fd8743012a4f1ada5ee5968b1b3619c427ba" }
|
||||
|
||||
[patch."https://github.com/ralexstokes/mev-rs"]
|
||||
mev-rs = { git = "https://github.com/ralexstokes//mev-rs", rev = "7813d4a4a564e0754e9aaab2d95520ba437c3889" }
|
||||
[patch."https://github.com/ralexstokes/ethereum-consensus"]
|
||||
ethereum-consensus = { git = "https://github.com/ralexstokes//ethereum-consensus", rev = "9b0ee0a8a45b968c8df5e7e64ea1c094e16f053d" }
|
||||
[patch."https://github.com/ralexstokes/ssz-rs"]
|
||||
ssz-rs = { git = "https://github.com/ralexstokes//ssz-rs", rev = "adf1a0b14cef90b9536f28ef89da1fab316465e1" }
|
||||
|
||||
[profile.maxperf]
|
||||
inherits = "release"
|
||||
lto = "fat"
|
||||
|
@ -41,9 +41,9 @@ lazy_static = "1.4.0"
|
||||
ethers-core = "1.0.2"
|
||||
builder_client = { path = "../builder_client" }
|
||||
fork_choice = { path = "../../consensus/fork_choice" }
|
||||
mev-build-rs = { git = "https://github.com/ralexstokes/mev-rs", rev = "6c99b0fbdc0427b1625469d2e575303ce08de5b8" }
|
||||
ethereum-consensus = { git = "https://github.com/ralexstokes/ethereum-consensus", rev = "a8110af76d97bf2bf27fb987a671808fcbdf1834" }
|
||||
ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "cb08f1" }
|
||||
mev-rs = { git = "https://github.com/ralexstokes/mev-rs" }
|
||||
ethereum-consensus = { git = "https://github.com/ralexstokes/ethereum-consensus" }
|
||||
ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs" }
|
||||
tokio-stream = { version = "0.1.9", features = [ "sync" ] }
|
||||
strum = "0.24.0"
|
||||
keccak-hash = "0.10.0"
|
||||
|
@ -36,7 +36,8 @@ use tokio::{
|
||||
time::sleep,
|
||||
};
|
||||
use tokio_stream::wrappers::WatchStream;
|
||||
use types::{AbstractExecPayload, BeaconStateError, Blob, ExecPayload, KzgCommitment};
|
||||
use tree_hash::TreeHash;
|
||||
use types::{AbstractExecPayload, BeaconStateError, Blob, ExecPayload, KzgCommitment, Withdrawals};
|
||||
use types::{
|
||||
BlindedPayload, BlockType, ChainSpec, Epoch, ExecutionBlockHash, ExecutionPayload,
|
||||
ExecutionPayloadCapella, ExecutionPayloadEip4844, ExecutionPayloadMerge, ForkName,
|
||||
@ -1874,10 +1875,9 @@ enum InvalidBuilderPayload {
|
||||
signature: Signature,
|
||||
pubkey: PublicKeyBytes,
|
||||
},
|
||||
#[allow(dead_code)]
|
||||
WithdrawalsRoot {
|
||||
payload: Hash256,
|
||||
expected: Hash256,
|
||||
payload: Option<Hash256>,
|
||||
expected: Option<Hash256>,
|
||||
},
|
||||
}
|
||||
|
||||
@ -1930,10 +1930,16 @@ impl fmt::Display for InvalidBuilderPayload {
|
||||
signature, pubkey
|
||||
),
|
||||
InvalidBuilderPayload::WithdrawalsRoot { payload, expected } => {
|
||||
let opt_string = |opt_hash: &Option<Hash256>| {
|
||||
opt_hash
|
||||
.map(|hash| hash.to_string())
|
||||
.unwrap_or_else(|| "None".to_string())
|
||||
};
|
||||
write!(
|
||||
f,
|
||||
"payload withdrawals root was {} not {}",
|
||||
payload, expected
|
||||
opt_string(payload),
|
||||
opt_string(expected)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -1964,6 +1970,13 @@ fn verify_builder_bid<T: EthSpec, Payload: AbstractExecPayload<T>>(
|
||||
);
|
||||
}
|
||||
|
||||
let expected_withdrawals_root = payload_attributes
|
||||
.withdrawals()
|
||||
.ok()
|
||||
.cloned()
|
||||
.map(|withdrawals| Withdrawals::<T>::from(withdrawals).tree_hash_root());
|
||||
let payload_withdrawals_root = header.withdrawals_root().ok();
|
||||
|
||||
if payload_value < profit_threshold {
|
||||
Err(Box::new(InvalidBuilderPayload::LowValue {
|
||||
profit_threshold,
|
||||
@ -1999,6 +2012,11 @@ fn verify_builder_bid<T: EthSpec, Payload: AbstractExecPayload<T>>(
|
||||
signature: bid.data.signature.clone(),
|
||||
pubkey: bid.data.message.pubkey,
|
||||
}))
|
||||
} else if payload_withdrawals_root != expected_withdrawals_root {
|
||||
Err(Box::new(InvalidBuilderPayload::WithdrawalsRoot {
|
||||
payload: payload_withdrawals_root,
|
||||
expected: expected_withdrawals_root,
|
||||
}))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
@ -3,15 +3,19 @@ use crate::{Config, ExecutionLayer, PayloadAttributes};
|
||||
use async_trait::async_trait;
|
||||
use eth2::types::{BlockId, StateId, ValidatorId};
|
||||
use eth2::{BeaconNodeHttpClient, Timeouts};
|
||||
use ethereum_consensus::crypto::{SecretKey, Signature};
|
||||
use ethereum_consensus::primitives::BlsPublicKey;
|
||||
pub use ethereum_consensus::state_transition::Context;
|
||||
use ethereum_consensus::{
|
||||
crypto::{SecretKey, Signature},
|
||||
primitives::{BlsPublicKey, BlsSignature, ExecutionAddress, Hash32, Root, U256},
|
||||
state_transition::Error,
|
||||
};
|
||||
use fork_choice::ForkchoiceUpdateParameters;
|
||||
use mev_build_rs::{
|
||||
use mev_rs::{
|
||||
bellatrix::{BuilderBid as BuilderBidBellatrix, SignedBuilderBid as SignedBuilderBidBellatrix},
|
||||
capella::{BuilderBid as BuilderBidCapella, SignedBuilderBid as SignedBuilderBidCapella},
|
||||
sign_builder_message, verify_signed_builder_message, BidRequest, BlindedBlockProviderError,
|
||||
BlindedBlockProviderServer, BuilderBid, ExecutionPayload as ServerPayload,
|
||||
ExecutionPayloadHeader as ServerPayloadHeader, SignedBlindedBeaconBlock, SignedBuilderBid,
|
||||
SignedValidatorRegistration,
|
||||
SignedBlindedBeaconBlock, SignedBuilderBid, SignedValidatorRegistration,
|
||||
};
|
||||
use parking_lot::RwLock;
|
||||
use sensitive_url::SensitiveUrl;
|
||||
@ -39,25 +43,129 @@ pub enum Operation {
|
||||
PrevRandao(Hash256),
|
||||
BlockNumber(usize),
|
||||
Timestamp(usize),
|
||||
WithdrawalsRoot(Hash256),
|
||||
}
|
||||
|
||||
impl Operation {
|
||||
fn apply(self, bid: &mut BuilderBid) -> Result<(), BlindedBlockProviderError> {
|
||||
fn apply<B: BidStuff>(self, bid: &mut B) -> Result<(), BlindedBlockProviderError> {
|
||||
match self {
|
||||
Operation::FeeRecipient(fee_recipient) => {
|
||||
bid.header.fee_recipient = to_ssz_rs(&fee_recipient)?
|
||||
*bid.fee_recipient_mut() = to_ssz_rs(&fee_recipient)?
|
||||
}
|
||||
Operation::GasLimit(gas_limit) => bid.header.gas_limit = gas_limit as u64,
|
||||
Operation::Value(value) => bid.value = to_ssz_rs(&value)?,
|
||||
Operation::ParentHash(parent_hash) => bid.header.parent_hash = to_ssz_rs(&parent_hash)?,
|
||||
Operation::PrevRandao(prev_randao) => bid.header.prev_randao = to_ssz_rs(&prev_randao)?,
|
||||
Operation::BlockNumber(block_number) => bid.header.block_number = block_number as u64,
|
||||
Operation::Timestamp(timestamp) => bid.header.timestamp = timestamp as u64,
|
||||
Operation::GasLimit(gas_limit) => *bid.gas_limit_mut() = gas_limit as u64,
|
||||
Operation::Value(value) => *bid.value_mut() = to_ssz_rs(&value)?,
|
||||
Operation::ParentHash(parent_hash) => *bid.parent_hash_mut() = to_ssz_rs(&parent_hash)?,
|
||||
Operation::PrevRandao(prev_randao) => *bid.prev_randao_mut() = to_ssz_rs(&prev_randao)?,
|
||||
Operation::BlockNumber(block_number) => *bid.block_number_mut() = block_number as u64,
|
||||
Operation::Timestamp(timestamp) => *bid.timestamp_mut() = timestamp as u64,
|
||||
Operation::WithdrawalsRoot(root) => *bid.withdrawals_root_mut()? = to_ssz_rs(&root)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// contains functions we need for BuilderBids.. not sure what to call this
|
||||
pub trait BidStuff {
|
||||
fn fee_recipient_mut(&mut self) -> &mut ExecutionAddress;
|
||||
fn gas_limit_mut(&mut self) -> &mut u64;
|
||||
fn value_mut(&mut self) -> &mut U256;
|
||||
fn parent_hash_mut(&mut self) -> &mut Hash32;
|
||||
fn prev_randao_mut(&mut self) -> &mut Hash32;
|
||||
fn block_number_mut(&mut self) -> &mut u64;
|
||||
fn timestamp_mut(&mut self) -> &mut u64;
|
||||
fn withdrawals_root_mut(&mut self) -> Result<&mut Root, BlindedBlockProviderError>;
|
||||
|
||||
fn sign_builder_message(
|
||||
&mut self,
|
||||
signing_key: &SecretKey,
|
||||
context: &Context,
|
||||
) -> Result<BlsSignature, Error>;
|
||||
|
||||
fn to_signed_bid(self, signature: BlsSignature) -> SignedBuilderBid;
|
||||
}
|
||||
|
||||
impl BidStuff for BuilderBid {
|
||||
fn fee_recipient_mut(&mut self) -> &mut ExecutionAddress {
|
||||
match self {
|
||||
Self::Bellatrix(bid) => &mut bid.header.fee_recipient,
|
||||
Self::Capella(bid) => &mut bid.header.fee_recipient,
|
||||
}
|
||||
}
|
||||
|
||||
fn gas_limit_mut(&mut self) -> &mut u64 {
|
||||
match self {
|
||||
Self::Bellatrix(bid) => &mut bid.header.gas_limit,
|
||||
Self::Capella(bid) => &mut bid.header.gas_limit,
|
||||
}
|
||||
}
|
||||
|
||||
fn value_mut(&mut self) -> &mut U256 {
|
||||
match self {
|
||||
Self::Bellatrix(bid) => &mut bid.value,
|
||||
Self::Capella(bid) => &mut bid.value,
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_hash_mut(&mut self) -> &mut Hash32 {
|
||||
match self {
|
||||
Self::Bellatrix(bid) => &mut bid.header.parent_hash,
|
||||
Self::Capella(bid) => &mut bid.header.parent_hash,
|
||||
}
|
||||
}
|
||||
|
||||
fn prev_randao_mut(&mut self) -> &mut Hash32 {
|
||||
match self {
|
||||
Self::Bellatrix(bid) => &mut bid.header.prev_randao,
|
||||
Self::Capella(bid) => &mut bid.header.prev_randao,
|
||||
}
|
||||
}
|
||||
|
||||
fn block_number_mut(&mut self) -> &mut u64 {
|
||||
match self {
|
||||
Self::Bellatrix(bid) => &mut bid.header.block_number,
|
||||
Self::Capella(bid) => &mut bid.header.block_number,
|
||||
}
|
||||
}
|
||||
|
||||
fn timestamp_mut(&mut self) -> &mut u64 {
|
||||
match self {
|
||||
Self::Bellatrix(bid) => &mut bid.header.timestamp,
|
||||
Self::Capella(bid) => &mut bid.header.timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
fn withdrawals_root_mut(&mut self) -> Result<&mut Root, BlindedBlockProviderError> {
|
||||
match self {
|
||||
Self::Bellatrix(_) => Err(BlindedBlockProviderError::Custom(
|
||||
"withdrawals_root called on bellatrix bid".to_string(),
|
||||
)),
|
||||
Self::Capella(bid) => Ok(&mut bid.header.withdrawals_root),
|
||||
}
|
||||
}
|
||||
|
||||
fn sign_builder_message(
|
||||
&mut self,
|
||||
signing_key: &SecretKey,
|
||||
context: &Context,
|
||||
) -> Result<Signature, Error> {
|
||||
match self {
|
||||
Self::Bellatrix(message) => sign_builder_message(message, signing_key, context),
|
||||
Self::Capella(message) => sign_builder_message(message, signing_key, context),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_signed_bid(self, signature: Signature) -> SignedBuilderBid {
|
||||
match self {
|
||||
Self::Bellatrix(message) => {
|
||||
SignedBuilderBid::Bellatrix(SignedBuilderBidBellatrix { message, signature })
|
||||
}
|
||||
Self::Capella(message) => {
|
||||
SignedBuilderBid::Capella(SignedBuilderBidCapella { message, signature })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TestingBuilder<E: EthSpec> {
|
||||
server: BlindedBlockProviderServer<MockBuilder<E>>,
|
||||
pub builder: MockBuilder<E>,
|
||||
@ -112,7 +220,10 @@ impl<E: EthSpec> TestingBuilder<E> {
|
||||
}
|
||||
|
||||
pub async fn run(&self) {
|
||||
self.server.run().await
|
||||
let server = self.server.serve();
|
||||
if let Err(err) = server.await {
|
||||
println!("error while listening for incoming: {err}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,7 +274,7 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
*self.invalidate_signatures.write() = false;
|
||||
}
|
||||
|
||||
fn apply_operations(&self, bid: &mut BuilderBid) -> Result<(), BlindedBlockProviderError> {
|
||||
fn apply_operations<B: BidStuff>(&self, bid: &mut B) -> Result<(), BlindedBlockProviderError> {
|
||||
let mut guard = self.operations.write();
|
||||
while let Some(op) = guard.pop() {
|
||||
op.apply(bid)?;
|
||||
@ -173,7 +284,7 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<E: EthSpec> mev_build_rs::BlindedBlockProvider for MockBuilder<E> {
|
||||
impl<E: EthSpec> mev_rs::BlindedBlockProvider for MockBuilder<E> {
|
||||
async fn register_validators(
|
||||
&self,
|
||||
registrations: &mut [SignedValidatorRegistration],
|
||||
@ -201,6 +312,7 @@ impl<E: EthSpec> mev_build_rs::BlindedBlockProvider for MockBuilder<E> {
|
||||
bid_request: &BidRequest,
|
||||
) -> Result<SignedBuilderBid, BlindedBlockProviderError> {
|
||||
let slot = Slot::new(bid_request.slot);
|
||||
let fork = self.spec.fork_name_at_slot::<E>(slot);
|
||||
let signed_cached_data = self
|
||||
.val_registration_cache
|
||||
.read()
|
||||
@ -216,9 +328,13 @@ impl<E: EthSpec> mev_build_rs::BlindedBlockProvider for MockBuilder<E> {
|
||||
.map_err(convert_err)?
|
||||
.ok_or_else(|| convert_err("missing head block"))?;
|
||||
|
||||
let block = head.data.message_merge().map_err(convert_err)?;
|
||||
let block = head.data.message();
|
||||
let head_block_root = block.tree_hash_root();
|
||||
let head_execution_hash = block.body.execution_payload.execution_payload.block_hash;
|
||||
let head_execution_hash = block
|
||||
.body()
|
||||
.execution_payload()
|
||||
.map_err(convert_err)?
|
||||
.block_hash();
|
||||
if head_execution_hash != from_ssz_rs(&bid_request.parent_hash)? {
|
||||
return Err(BlindedBlockProviderError::Custom(format!(
|
||||
"head mismatch: {} {}",
|
||||
@ -233,12 +349,11 @@ impl<E: EthSpec> mev_build_rs::BlindedBlockProvider for MockBuilder<E> {
|
||||
.map_err(convert_err)?
|
||||
.ok_or_else(|| convert_err("missing finalized block"))?
|
||||
.data
|
||||
.message_merge()
|
||||
.message()
|
||||
.body()
|
||||
.execution_payload()
|
||||
.map_err(convert_err)?
|
||||
.body
|
||||
.execution_payload
|
||||
.execution_payload
|
||||
.block_hash;
|
||||
.block_hash();
|
||||
|
||||
let justified_execution_hash = self
|
||||
.beacon_client
|
||||
@ -247,12 +362,11 @@ impl<E: EthSpec> mev_build_rs::BlindedBlockProvider for MockBuilder<E> {
|
||||
.map_err(convert_err)?
|
||||
.ok_or_else(|| convert_err("missing finalized block"))?
|
||||
.data
|
||||
.message_merge()
|
||||
.message()
|
||||
.body()
|
||||
.execution_payload()
|
||||
.map_err(convert_err)?
|
||||
.body
|
||||
.execution_payload
|
||||
.execution_payload
|
||||
.block_hash;
|
||||
.block_hash();
|
||||
|
||||
let val_index = self
|
||||
.beacon_client
|
||||
@ -288,12 +402,22 @@ impl<E: EthSpec> mev_build_rs::BlindedBlockProvider for MockBuilder<E> {
|
||||
.get_randao_mix(head_state.current_epoch())
|
||||
.map_err(convert_err)?;
|
||||
|
||||
// FIXME: think about proper fork here
|
||||
let payload_attributes =
|
||||
PayloadAttributes::new(timestamp, *prev_randao, fee_recipient, None);
|
||||
let payload_attributes = match fork {
|
||||
ForkName::Merge => PayloadAttributes::new(timestamp, *prev_randao, fee_recipient, None),
|
||||
// the withdrawals root is filled in by operations
|
||||
ForkName::Capella | ForkName::Eip4844 => {
|
||||
PayloadAttributes::new(timestamp, *prev_randao, fee_recipient, Some(vec![]))
|
||||
}
|
||||
ForkName::Base | ForkName::Altair => {
|
||||
return Err(BlindedBlockProviderError::Custom(format!(
|
||||
"Unsupported fork: {}",
|
||||
fork
|
||||
)));
|
||||
}
|
||||
};
|
||||
|
||||
self.el
|
||||
.insert_proposer(slot, head_block_root, val_index, payload_attributes)
|
||||
.insert_proposer(slot, head_block_root, val_index, payload_attributes.clone())
|
||||
.await;
|
||||
|
||||
let forkchoice_update_params = ForkchoiceUpdateParameters {
|
||||
@ -303,17 +427,13 @@ impl<E: EthSpec> mev_build_rs::BlindedBlockProvider for MockBuilder<E> {
|
||||
finalized_hash: Some(finalized_execution_hash),
|
||||
};
|
||||
|
||||
let payload_attributes =
|
||||
PayloadAttributes::new(timestamp, *prev_randao, fee_recipient, None);
|
||||
|
||||
let payload = self
|
||||
.el
|
||||
.get_full_payload_caching::<BlindedPayload<E>>(
|
||||
head_execution_hash,
|
||||
&payload_attributes,
|
||||
forkchoice_update_params,
|
||||
// TODO: do we need to write a test for this if this is Capella fork?
|
||||
ForkName::Merge,
|
||||
fork,
|
||||
)
|
||||
.await
|
||||
.map_err(convert_err)?
|
||||
@ -321,44 +441,54 @@ impl<E: EthSpec> mev_build_rs::BlindedBlockProvider for MockBuilder<E> {
|
||||
.to_execution_payload_header();
|
||||
|
||||
let json_payload = serde_json::to_string(&payload).map_err(convert_err)?;
|
||||
let mut header: ServerPayloadHeader =
|
||||
serde_json::from_str(json_payload.as_str()).map_err(convert_err)?;
|
||||
|
||||
header.gas_limit = cached_data.gas_limit;
|
||||
|
||||
let mut message = BuilderBid {
|
||||
header,
|
||||
let mut message = match fork {
|
||||
ForkName::Capella => BuilderBid::Capella(BuilderBidCapella {
|
||||
header: serde_json::from_str(json_payload.as_str()).map_err(convert_err)?,
|
||||
value: to_ssz_rs(&Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI))?,
|
||||
public_key: self.builder_sk.public_key(),
|
||||
}),
|
||||
ForkName::Merge => BuilderBid::Bellatrix(BuilderBidBellatrix {
|
||||
header: serde_json::from_str(json_payload.as_str()).map_err(convert_err)?,
|
||||
value: to_ssz_rs(&Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI))?,
|
||||
public_key: self.builder_sk.public_key(),
|
||||
}),
|
||||
ForkName::Base | ForkName::Altair | ForkName::Eip4844 => {
|
||||
return Err(BlindedBlockProviderError::Custom(format!(
|
||||
"Unsupported fork: {}",
|
||||
fork
|
||||
)))
|
||||
}
|
||||
};
|
||||
*message.gas_limit_mut() = cached_data.gas_limit;
|
||||
|
||||
self.apply_operations(&mut message)?;
|
||||
|
||||
let mut signature =
|
||||
sign_builder_message(&mut message, &self.builder_sk, self.context.as_ref())?;
|
||||
message.sign_builder_message(&self.builder_sk, self.context.as_ref())?;
|
||||
|
||||
if *self.invalidate_signatures.read() {
|
||||
signature = Signature::default();
|
||||
}
|
||||
|
||||
let signed_bid = SignedBuilderBid { message, signature };
|
||||
Ok(signed_bid)
|
||||
Ok(message.to_signed_bid(signature))
|
||||
}
|
||||
|
||||
async fn open_bid(
|
||||
&self,
|
||||
signed_block: &mut SignedBlindedBeaconBlock,
|
||||
) -> Result<ServerPayload, BlindedBlockProviderError> {
|
||||
let node = match signed_block {
|
||||
SignedBlindedBeaconBlock::Bellatrix(block) => {
|
||||
block.message.body.execution_payload_header.hash_tree_root()
|
||||
}
|
||||
SignedBlindedBeaconBlock::Capella(block) => {
|
||||
block.message.body.execution_payload_header.hash_tree_root()
|
||||
}
|
||||
}
|
||||
.map_err(convert_err)?;
|
||||
|
||||
let payload = self
|
||||
.el
|
||||
.get_payload_by_root(&from_ssz_rs(
|
||||
&signed_block
|
||||
.message
|
||||
.body
|
||||
.execution_payload_header
|
||||
.hash_tree_root()
|
||||
.map_err(convert_err)?,
|
||||
)?)
|
||||
.get_payload_by_root(&from_ssz_rs(&node)?)
|
||||
.ok_or_else(|| convert_err("missing payload for tx root"))?;
|
||||
|
||||
let json_payload = serde_json::to_string(&payload).map_err(convert_err)?;
|
||||
|
@ -24,6 +24,7 @@ use network::NetworkReceivers;
|
||||
use proto_array::ExecutionStatus;
|
||||
use sensitive_url::SensitiveUrl;
|
||||
use slot_clock::SlotClock;
|
||||
use state_processing::per_block_processing::get_expected_withdrawals;
|
||||
use state_processing::per_slot_processing;
|
||||
use std::convert::TryInto;
|
||||
use std::sync::Arc;
|
||||
@ -3428,6 +3429,98 @@ impl ApiTester {
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn test_builder_works_post_capella(self) -> Self {
|
||||
// Ensure builder payload is chosen
|
||||
self.mock_builder
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.builder
|
||||
.add_operation(Operation::Value(Uint256::from(
|
||||
DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI + 1,
|
||||
)));
|
||||
|
||||
let slot = self.chain.slot().unwrap();
|
||||
let propose_state = self
|
||||
.harness
|
||||
.chain
|
||||
.state_at_slot(slot, StateSkipConfig::WithoutStateRoots)
|
||||
.unwrap();
|
||||
let withdrawals = get_expected_withdrawals(&propose_state, &self.chain.spec).unwrap();
|
||||
let withdrawals_root = withdrawals.tree_hash_root();
|
||||
// Set withdrawals root for builder
|
||||
self.mock_builder
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.builder
|
||||
.add_operation(Operation::WithdrawalsRoot(withdrawals_root));
|
||||
|
||||
let epoch = self.chain.epoch().unwrap();
|
||||
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
||||
|
||||
let payload: BlindedPayload<E> = self
|
||||
.client
|
||||
.get_validator_blinded_blocks::<E, BlindedPayload<E>>(slot, &randao_reveal, None)
|
||||
.await
|
||||
.unwrap()
|
||||
.data
|
||||
.body()
|
||||
.execution_payload()
|
||||
.unwrap()
|
||||
.into();
|
||||
|
||||
// The builder's payload should've been chosen, so this cache should not be populated
|
||||
assert!(self
|
||||
.chain
|
||||
.execution_layer
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.get_payload_by_root(&payload.tree_hash_root())
|
||||
.is_none());
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn test_lighthouse_rejects_invalid_withdrawals_root(self) -> Self {
|
||||
// Ensure builder payload *would be* chosen
|
||||
self.mock_builder
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.builder
|
||||
.add_operation(Operation::Value(Uint256::from(
|
||||
DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI + 1,
|
||||
)));
|
||||
// Set withdrawals root to something invalid
|
||||
self.mock_builder
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.builder
|
||||
.add_operation(Operation::WithdrawalsRoot(Hash256::repeat_byte(0x42)));
|
||||
|
||||
let slot = self.chain.slot().unwrap();
|
||||
let epoch = self.chain.epoch().unwrap();
|
||||
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
||||
|
||||
let payload: BlindedPayload<E> = self
|
||||
.client
|
||||
.get_validator_blinded_blocks::<E, BlindedPayload<E>>(slot, &randao_reveal, None)
|
||||
.await
|
||||
.unwrap()
|
||||
.data
|
||||
.body()
|
||||
.execution_payload()
|
||||
.unwrap()
|
||||
.into();
|
||||
|
||||
// The local payload should've been chosen because the builder's was invalid
|
||||
assert!(self
|
||||
.chain
|
||||
.execution_layer
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.get_payload_by_root(&payload.tree_hash_root())
|
||||
.is_some());
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub async fn test_get_lighthouse_health(self) -> Self {
|
||||
self.client.get_lighthouse_health().await.unwrap();
|
||||
@ -4424,6 +4517,26 @@ async fn builder_payload_chosen_by_profit() {
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn builder_works_post_capella() {
|
||||
let mut config = ApiTesterConfig {
|
||||
builder_threshold: Some(0),
|
||||
spec: E::default_spec(),
|
||||
};
|
||||
config.spec.altair_fork_epoch = Some(Epoch::new(0));
|
||||
config.spec.bellatrix_fork_epoch = Some(Epoch::new(0));
|
||||
config.spec.capella_fork_epoch = Some(Epoch::new(0));
|
||||
|
||||
ApiTester::new_from_config(config)
|
||||
.await
|
||||
.test_post_validator_register_validator()
|
||||
.await
|
||||
.test_builder_works_post_capella()
|
||||
.await
|
||||
.test_lighthouse_rejects_invalid_withdrawals_root()
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn lighthouse_endpoints() {
|
||||
ApiTester::new()
|
||||
|
Loading…
Reference in New Issue
Block a user