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:
ethDreamer 2023-02-10 13:30:14 -06:00 committed by GitHub
parent 39f8327f73
commit e743d75c9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 344 additions and 75 deletions

19
Cargo.lock generated
View File

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

View File

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

View File

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

View File

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

View File

@ -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,
value: to_ssz_rs(&Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI))?,
public_key: self.builder_sk.public_key(),
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)?;

View File

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