Add Deneb builder test & update mock builder (#4607)

* Update mock builder, mev-rs dependencies, eth2 lib to support deneb builder flow

* Replace `sharingForkTime` with `cancunTime`

* Patch `ethereum-consensus` to include some deneb-devnet-8 changes

* Add deneb builder test and fix block contents deserialization

* Fix builder bid encoding issue and passing deneb builder test \o/

* Fix test compilation

* Revert `cancunTime` change in genesis to pass doppelganger tests
This commit is contained in:
Jimmy Chen 2023-08-19 10:12:09 +10:00 committed by GitHub
parent f031a570ce
commit 4898430330
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 440 additions and 130 deletions

146
Cargo.lock generated
View File

@ -18,7 +18,7 @@ version = "0.3.5"
dependencies = [ dependencies = [
"account_utils", "account_utils",
"bls", "bls",
"clap", "clap 2.34.0",
"clap_utils", "clap_utils",
"directory", "directory",
"environment", "environment",
@ -183,6 +183,55 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "anstream"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is-terminal",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd"
[[package]]
name = "anstyle-parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]] [[package]]
name = "anvil-rpc" name = "anvil-rpc"
version = "0.1.0" version = "0.1.0"
@ -479,8 +528,9 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]] [[package]]
name = "beacon-api-client" name = "beacon-api-client"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/ralexstokes/beacon-api-client?rev=93d7e8c#93d7e8c38fe9782c4862909663e7b57c44f805a9" source = "git+https://github.com/ralexstokes/beacon-api-client?rev=56a290c#56a290ca9d2c67086917a0929cdf2fe35e5f917f"
dependencies = [ dependencies = [
"clap 4.3.21",
"ethereum-consensus", "ethereum-consensus",
"http", "http",
"itertools", "itertools",
@ -562,7 +612,7 @@ name = "beacon_node"
version = "4.3.0" version = "4.3.0"
dependencies = [ dependencies = [
"beacon_chain", "beacon_chain",
"clap", "clap 2.34.0",
"clap_utils", "clap_utils",
"client", "client",
"directory", "directory",
@ -785,7 +835,7 @@ name = "boot_node"
version = "4.3.0" version = "4.3.0"
dependencies = [ dependencies = [
"beacon_node", "beacon_node",
"clap", "clap 2.34.0",
"clap_utils", "clap_utils",
"eth2_network_config", "eth2_network_config",
"ethereum_ssz", "ethereum_ssz",
@ -1067,11 +1117,52 @@ dependencies = [
"vec_map", "vec_map",
] ]
[[package]]
name = "clap"
version = "4.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c27cdf28c0f604ba3f512b0c9a409f8de8513e4816705deb0498b627e7c3a3fd"
dependencies = [
"clap_builder",
"clap_derive",
"once_cell",
]
[[package]]
name = "clap_builder"
version = "4.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08a9f1ab5e9f01a9b81f202e8562eb9a10de70abf9eaeac1be465c28b75aa4aa"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim 0.10.0",
]
[[package]]
name = "clap_derive"
version = "4.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.28",
]
[[package]]
name = "clap_lex"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
[[package]] [[package]]
name = "clap_utils" name = "clap_utils"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"clap", "clap 2.34.0",
"dirs", "dirs",
"eth2_network_config", "eth2_network_config",
"ethereum-types 0.14.1", "ethereum-types 0.14.1",
@ -1135,6 +1226,12 @@ dependencies = [
"cc", "cc",
] ]
[[package]]
name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]] [[package]]
name = "compare_fields" name = "compare_fields"
version = "0.2.0" version = "0.2.0"
@ -1222,7 +1319,7 @@ checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f"
dependencies = [ dependencies = [
"atty", "atty",
"cast", "cast",
"clap", "clap 2.34.0",
"criterion-plot", "criterion-plot",
"csv", "csv",
"itertools", "itertools",
@ -1508,7 +1605,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"beacon_chain", "beacon_chain",
"beacon_node", "beacon_node",
"clap", "clap 2.34.0",
"clap_utils", "clap_utils",
"environment", "environment",
"logging", "logging",
@ -1683,7 +1780,7 @@ dependencies = [
name = "directory" name = "directory"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"clap", "clap 2.34.0",
"clap_utils", "clap_utils",
"eth2_network_config", "eth2_network_config",
] ]
@ -2317,7 +2414,7 @@ dependencies = [
[[package]] [[package]]
name = "ethereum-consensus" name = "ethereum-consensus"
version = "0.1.1" version = "0.1.1"
source = "git+https://github.com/ralexstokes/ethereum-consensus?rev=e380108#e380108d15fcc40349927fdf3d11c71f9edb67c2" source = "git+https://github.com/jimmygchen/ethereum-consensus?rev=2354493#2354493fd631b736c189868b7dc1b415a160f0f7"
dependencies = [ dependencies = [
"async-stream", "async-stream",
"blst", "blst",
@ -3724,6 +3821,17 @@ version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6"
[[package]]
name = "is-terminal"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
dependencies = [
"hermit-abi 0.3.2",
"rustix 0.38.4",
"windows-sys",
]
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.10.5" version = "0.10.5"
@ -3879,7 +3987,7 @@ dependencies = [
"account_utils", "account_utils",
"beacon_chain", "beacon_chain",
"bls", "bls",
"clap", "clap 2.34.0",
"clap_utils", "clap_utils",
"deposit_contract", "deposit_contract",
"directory", "directory",
@ -4433,7 +4541,7 @@ dependencies = [
"beacon_processor", "beacon_processor",
"bls", "bls",
"boot_node", "boot_node",
"clap", "clap 2.34.0",
"clap_utils", "clap_utils",
"database_manager", "database_manager",
"directory", "directory",
@ -4799,7 +4907,7 @@ dependencies = [
[[package]] [[package]]
name = "mev-rs" name = "mev-rs"
version = "0.3.0" version = "0.3.0"
source = "git+https://github.com/ralexstokes/mev-rs?rev=216657016d5c0889b505857c89ae42c7aa2764af#216657016d5c0889b505857c89ae42c7aa2764af" source = "git+https://github.com/ralexstokes/mev-rs?rev=9d88a2386b58c2948fa850f0dd4b3dfe18bd4962#9d88a2386b58c2948fa850f0dd4b3dfe18bd4962"
dependencies = [ dependencies = [
"anvil-rpc", "anvil-rpc",
"async-trait", "async-trait",
@ -7147,7 +7255,7 @@ dependencies = [
name = "simulator" name = "simulator"
version = "0.2.0" version = "0.2.0"
dependencies = [ dependencies = [
"clap", "clap 2.34.0",
"env_logger 0.9.3", "env_logger 0.9.3",
"eth1", "eth1",
"eth1_test_rig", "eth1_test_rig",
@ -8659,6 +8767,12 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "0.8.2" version = "0.8.2"
@ -8676,7 +8790,7 @@ dependencies = [
"account_utils", "account_utils",
"bincode", "bincode",
"bls", "bls",
"clap", "clap 2.34.0",
"clap_utils", "clap_utils",
"deposit_contract", "deposit_contract",
"directory", "directory",
@ -8749,7 +8863,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"account_utils", "account_utils",
"bls", "bls",
"clap", "clap 2.34.0",
"clap_utils", "clap_utils",
"environment", "environment",
"eth2", "eth2",
@ -8992,7 +9106,7 @@ dependencies = [
"beacon_node", "beacon_node",
"bls", "bls",
"byteorder", "byteorder",
"clap", "clap 2.34.0",
"diesel", "diesel",
"diesel_migrations", "diesel_migrations",
"env_logger 0.9.3", "env_logger 0.9.3",

View File

@ -94,6 +94,10 @@ resolver = "2"
[patch.crates-io] [patch.crates-io]
warp = { git = "https://github.com/macladson/warp", rev="7e75acc368229a46a236a8c991bf251fe7fe50ef" } warp = { git = "https://github.com/macladson/warp", rev="7e75acc368229a46a236a8c991bf251fe7fe50ef" }
# PR: https://github.com/ralexstokes/ethereum-consensus/pull/213
[patch."https://github.com/ralexstokes/ethereum-consensus"]
ethereum-consensus = { git = "https://github.com/jimmygchen/ethereum-consensus", rev = "2354493" }
[profile.maxperf] [profile.maxperf]
inherits = "release" inherits = "release"
lto = "fat" lto = "fat"

View File

@ -118,6 +118,7 @@ use store::{
use task_executor::{ShutdownReason, TaskExecutor}; use task_executor::{ShutdownReason, TaskExecutor};
use tokio_stream::Stream; use tokio_stream::Stream;
use tree_hash::TreeHash; use tree_hash::TreeHash;
use types::beacon_block_body::{from_block_kzg_commitments, to_block_kzg_commitments};
use types::beacon_state::CloneConfig; use types::beacon_state::CloneConfig;
use types::blob_sidecar::{BlobItems, BlobSidecarList, FixedBlobSidecarList}; use types::blob_sidecar::{BlobItems, BlobSidecarList, FixedBlobSidecarList};
use types::consts::deneb::MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS; use types::consts::deneb::MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS;
@ -4925,6 +4926,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
.map_err(|_| BlockProductionError::InvalidPayloadFork)?, .map_err(|_| BlockProductionError::InvalidPayloadFork)?,
bls_to_execution_changes: bls_to_execution_changes.into(), bls_to_execution_changes: bls_to_execution_changes.into(),
blob_kzg_commitments: kzg_commitments blob_kzg_commitments: kzg_commitments
.map(to_block_kzg_commitments::<T::EthSpec>)
.ok_or(BlockProductionError::InvalidPayloadFork)?, .ok_or(BlockProductionError::InvalidPayloadFork)?,
}, },
}), }),
@ -4984,8 +4986,11 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
metrics::start_timer(&metrics::BLOCK_PRODUCTION_BLOBS_VERIFICATION_TIMES); metrics::start_timer(&metrics::BLOCK_PRODUCTION_BLOBS_VERIFICATION_TIMES);
let maybe_sidecar_list = match (blobs_opt, proofs_opt) { let maybe_sidecar_list = match (blobs_opt, proofs_opt) {
(Some(blobs_or_blobs_roots), Some(proofs)) => { (Some(blobs_or_blobs_roots), Some(proofs)) => {
let expected_kzg_commitments = let expected_kzg_commitments = block
block.body().blob_kzg_commitments().map_err(|_| { .body()
.blob_kzg_commitments()
.map(from_block_kzg_commitments::<T::EthSpec>)
.map_err(|_| {
BlockProductionError::InvalidBlockVariant( BlockProductionError::InvalidBlockVariant(
"deneb block does not contain kzg commitments".to_string(), "deneb block does not contain kzg commitments".to_string(),
) )
@ -5009,7 +5014,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
.ok_or(BlockProductionError::TrustedSetupNotInitialized)?; .ok_or(BlockProductionError::TrustedSetupNotInitialized)?;
kzg_utils::validate_blobs::<T::EthSpec>( kzg_utils::validate_blobs::<T::EthSpec>(
kzg, kzg,
expected_kzg_commitments, &expected_kzg_commitments,
blobs, blobs,
&kzg_proofs, &kzg_proofs,
) )
@ -5020,7 +5025,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
Sidecar::build_sidecar( Sidecar::build_sidecar(
blobs_or_blobs_roots, blobs_or_blobs_roots,
&block, &block,
expected_kzg_commitments, &expected_kzg_commitments,
kzg_proofs, kzg_proofs,
) )
.map_err(BlockProductionError::FailedToBuildBlobSidecars)?, .map_err(BlockProductionError::FailedToBuildBlobSidecars)?,

View File

@ -42,8 +42,8 @@ lazy_static = "1.4.0"
ethers-core = "1.0.2" ethers-core = "1.0.2"
builder_client = { path = "../builder_client" } builder_client = { path = "../builder_client" }
fork_choice = { path = "../../consensus/fork_choice" } fork_choice = { path = "../../consensus/fork_choice" }
mev-rs = { git = "https://github.com/ralexstokes/mev-rs", rev = "216657016d5c0889b505857c89ae42c7aa2764af" } mev-rs = { git = "https://github.com/ralexstokes/mev-rs", rev = "9d88a2386b58c2948fa850f0dd4b3dfe18bd4962" }
ethereum-consensus = { git = "https://github.com/ralexstokes/ethereum-consensus", rev = "e380108" } ethereum-consensus = { git = "https://github.com/ralexstokes/ethereum-consensus", rev = "56418ea" }
ssz_rs = "0.9.0" ssz_rs = "0.9.0"
tokio-stream = { version = "0.1.9", features = [ "sync" ] } tokio-stream = { version = "0.1.9", features = [ "sync" ] }
strum = "0.24.0" strum = "0.24.0"

View File

@ -18,6 +18,7 @@ use mev_rs::{
BuilderBid as BuilderBidBellatrix, SignedBuilderBid as SignedBuilderBidBellatrix, BuilderBid as BuilderBidBellatrix, SignedBuilderBid as SignedBuilderBidBellatrix,
}, },
capella::{BuilderBid as BuilderBidCapella, SignedBuilderBid as SignedBuilderBidCapella}, capella::{BuilderBid as BuilderBidCapella, SignedBuilderBid as SignedBuilderBidCapella},
deneb::{BuilderBid as BuilderBidDeneb, SignedBuilderBid as SignedBuilderBidDeneb},
BidRequest, BuilderBid, ExecutionPayload as ServerPayload, SignedBlindedBeaconBlock, BidRequest, BuilderBid, ExecutionPayload as ServerPayload, SignedBlindedBeaconBlock,
SignedBuilderBid, SignedValidatorRegistration, SignedBuilderBid, SignedValidatorRegistration,
}, },
@ -35,8 +36,9 @@ use std::time::Duration;
use task_executor::TaskExecutor; use task_executor::TaskExecutor;
use tempfile::NamedTempFile; use tempfile::NamedTempFile;
use tree_hash::TreeHash; use tree_hash::TreeHash;
use types::builder_bid::BlindedBlobsBundle;
use types::{ use types::{
Address, BeaconState, ChainSpec, EthSpec, ExecPayload, ExecutionPayload, Address, BeaconState, BlobsBundle, ChainSpec, EthSpec, ExecPayload, ExecutionPayload,
ExecutionPayloadHeader, ForkName, Hash256, Slot, Uint256, ExecutionPayloadHeader, ForkName, Hash256, Slot, Uint256,
}; };
@ -90,60 +92,50 @@ pub trait BidStuff {
fn to_signed_bid(self, signature: BlsSignature) -> SignedBuilderBid; fn to_signed_bid(self, signature: BlsSignature) -> SignedBuilderBid;
} }
macro_rules! map_builder_bid {
($self_ident:ident, |$var:ident| $expr:expr) => {
match $self_ident {
BuilderBid::Bellatrix($var) => $expr,
BuilderBid::Capella($var) => $expr,
BuilderBid::Deneb($var) => $expr,
}
};
}
impl BidStuff for BuilderBid { impl BidStuff for BuilderBid {
fn fee_recipient_mut(&mut self) -> &mut ExecutionAddress { fn fee_recipient_mut(&mut self) -> &mut ExecutionAddress {
match self { map_builder_bid!(self, |bid| &mut bid.header.fee_recipient)
Self::Bellatrix(bid) => &mut bid.header.fee_recipient,
Self::Capella(bid) => &mut bid.header.fee_recipient,
}
} }
fn gas_limit_mut(&mut self) -> &mut u64 { fn gas_limit_mut(&mut self) -> &mut u64 {
match self { map_builder_bid!(self, |bid| &mut bid.header.gas_limit)
Self::Bellatrix(bid) => &mut bid.header.gas_limit,
Self::Capella(bid) => &mut bid.header.gas_limit,
}
} }
fn value_mut(&mut self) -> &mut U256 { fn value_mut(&mut self) -> &mut U256 {
match self { map_builder_bid!(self, |bid| &mut bid.value)
Self::Bellatrix(bid) => &mut bid.value,
Self::Capella(bid) => &mut bid.value,
}
} }
fn parent_hash_mut(&mut self) -> &mut Hash32 { fn parent_hash_mut(&mut self) -> &mut Hash32 {
match self { map_builder_bid!(self, |bid| &mut bid.header.parent_hash)
Self::Bellatrix(bid) => &mut bid.header.parent_hash,
Self::Capella(bid) => &mut bid.header.parent_hash,
}
} }
fn prev_randao_mut(&mut self) -> &mut Hash32 { fn prev_randao_mut(&mut self) -> &mut Hash32 {
match self { map_builder_bid!(self, |bid| &mut bid.header.prev_randao)
Self::Bellatrix(bid) => &mut bid.header.prev_randao,
Self::Capella(bid) => &mut bid.header.prev_randao,
}
} }
fn block_number_mut(&mut self) -> &mut u64 { fn block_number_mut(&mut self) -> &mut u64 {
match self { map_builder_bid!(self, |bid| &mut bid.header.block_number)
Self::Bellatrix(bid) => &mut bid.header.block_number,
Self::Capella(bid) => &mut bid.header.block_number,
}
} }
fn timestamp_mut(&mut self) -> &mut u64 { fn timestamp_mut(&mut self) -> &mut u64 {
match self { map_builder_bid!(self, |bid| &mut bid.header.timestamp)
Self::Bellatrix(bid) => &mut bid.header.timestamp,
Self::Capella(bid) => &mut bid.header.timestamp,
}
} }
fn withdrawals_root_mut(&mut self) -> Result<&mut Root, MevError> { fn withdrawals_root_mut(&mut self) -> Result<&mut Root, MevError> {
match self { match self {
Self::Bellatrix(_) => Err(MevError::InvalidFork), Self::Bellatrix(_) => Err(MevError::InvalidFork),
Self::Capella(bid) => Ok(&mut bid.header.withdrawals_root), Self::Capella(bid) => Ok(&mut bid.header.withdrawals_root),
Self::Deneb(bid) => Ok(&mut bid.header.withdrawals_root),
} }
} }
@ -152,10 +144,11 @@ impl BidStuff for BuilderBid {
signing_key: &SecretKey, signing_key: &SecretKey,
context: &Context, context: &Context,
) -> Result<Signature, Error> { ) -> Result<Signature, Error> {
match self { map_builder_bid!(self, |message| sign_builder_message(
Self::Bellatrix(message) => sign_builder_message(message, signing_key, context), message,
Self::Capella(message) => sign_builder_message(message, signing_key, context), signing_key,
} context
))
} }
fn to_signed_bid(self, signature: Signature) -> SignedBuilderBid { fn to_signed_bid(self, signature: Signature) -> SignedBuilderBid {
@ -166,6 +159,9 @@ impl BidStuff for BuilderBid {
Self::Capella(message) => { Self::Capella(message) => {
SignedBuilderBid::Capella(SignedBuilderBidCapella { message, signature }) SignedBuilderBid::Capella(SignedBuilderBidCapella { message, signature })
} }
Self::Deneb(message) => {
SignedBuilderBid::Deneb(SignedBuilderBidDeneb { message, signature })
}
} }
} }
} }
@ -285,6 +281,10 @@ impl<E: EthSpec> MockBuilder<E> {
} }
Ok(()) Ok(())
} }
pub fn pubkey(&self) -> ethereum_consensus::crypto::PublicKey {
self.builder_sk.public_key()
}
} }
#[async_trait] #[async_trait]
@ -435,7 +435,11 @@ impl<E: EthSpec> mev_rs::BlindedBlockProvider for MockBuilder<E> {
finalized_hash: Some(finalized_execution_hash), finalized_hash: Some(finalized_execution_hash),
}; };
let payload: ExecutionPayload<E> = self let (payload, _block_value, maybe_blobs_bundle): (
ExecutionPayload<E>,
Uint256,
Option<BlobsBundle<E>>,
) = self
.el .el
.get_full_payload_caching( .get_full_payload_caching(
head_execution_hash, head_execution_hash,
@ -455,21 +459,28 @@ impl<E: EthSpec> mev_rs::BlindedBlockProvider for MockBuilder<E> {
ExecutionPayload::Deneb(payload) => ExecutionPayloadHeader::Deneb((&payload).into()), ExecutionPayload::Deneb(payload) => ExecutionPayloadHeader::Deneb((&payload).into()),
}; };
let json_payload = serde_json::to_string(&header).map_err(convert_err)?;
let mut message = match fork { let mut message = match fork {
ForkName::Deneb => {
let blinded_blobs: BlindedBlobsBundle<E> =
maybe_blobs_bundle.map(Into::into).unwrap_or_default();
BuilderBid::Deneb(BuilderBidDeneb {
header: to_ssz_rs(&header)?,
blinded_blobs_bundle: to_ssz_rs(&blinded_blobs)?,
value: to_ssz_rs(&Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI))?,
public_key: self.builder_sk.public_key(),
})
}
ForkName::Capella => BuilderBid::Capella(BuilderBidCapella { ForkName::Capella => BuilderBid::Capella(BuilderBidCapella {
header: serde_json::from_str(json_payload.as_str()).map_err(convert_err)?, header: to_ssz_rs(&header)?,
value: to_ssz_rs(&Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI))?, value: to_ssz_rs(&Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI))?,
public_key: self.builder_sk.public_key(), public_key: self.builder_sk.public_key(),
}), }),
ForkName::Merge => BuilderBid::Bellatrix(BuilderBidBellatrix { ForkName::Merge => BuilderBid::Bellatrix(BuilderBidBellatrix {
header: serde_json::from_str(json_payload.as_str()).map_err(convert_err)?, header: to_ssz_rs(&header)?,
value: to_ssz_rs(&Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI))?, value: to_ssz_rs(&Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI))?,
public_key: self.builder_sk.public_key(), public_key: self.builder_sk.public_key(),
}), }),
ForkName::Base | ForkName::Altair | ForkName::Deneb => { ForkName::Base | ForkName::Altair => return Err(MevError::InvalidFork),
return Err(MevError::InvalidFork)
}
}; };
*message.gas_limit_mut() = cached_data.gas_limit; *message.gas_limit_mut() = cached_data.gas_limit;
@ -495,6 +506,12 @@ impl<E: EthSpec> mev_rs::BlindedBlockProvider for MockBuilder<E> {
SignedBlindedBeaconBlock::Capella(block) => { SignedBlindedBeaconBlock::Capella(block) => {
block.message.body.execution_payload_header.hash_tree_root() block.message.body.execution_payload_header.hash_tree_root()
} }
SignedBlindedBeaconBlock::Deneb(block_and_blobs) => block_and_blobs
.signed_blinded_block
.message
.body
.execution_payload_header
.hash_tree_root(),
} }
.map_err(convert_err)?; .map_err(convert_err)?;
@ -521,12 +538,12 @@ pub fn to_ssz_rs<T: Encode, U: SimpleSerialize>(ssz_data: &T) -> Result<U, MevEr
ssz_rs::deserialize::<U>(&ssz_data.as_ssz_bytes()).map_err(convert_err) ssz_rs::deserialize::<U>(&ssz_data.as_ssz_bytes()).map_err(convert_err)
} }
fn convert_err<E: Debug>(e: E) -> MevError { pub fn convert_err<E: Debug>(e: E) -> MevError {
custom_err(format!("{e:?}")) custom_err(format!("{e:?}"))
} }
// This is a bit of a hack since the `Custom` variant was removed from `mev_rs::Error`. // This is a bit of a hack since the `Custom` variant was removed from `mev_rs::Error`.
fn custom_err(s: String) -> MevError { pub fn custom_err(s: String) -> MevError {
MevError::Consensus(ethereum_consensus::state_transition::Error::Io( MevError::Consensus(ethereum_consensus::state_transition::Error::Io(
std::io::Error::new(std::io::ErrorKind::Other, s), std::io::Error::new(std::io::ErrorKind::Other, s),
)) ))

View File

@ -29,7 +29,10 @@ pub use execution_block_generator::{
Block, ExecutionBlockGenerator, Block, ExecutionBlockGenerator,
}; };
pub use hook::Hook; pub use hook::Hook;
pub use mock_builder::{Context as MockBuilderContext, MockBuilder, Operation, TestingBuilder}; pub use mock_builder::{
convert_err, custom_err, from_ssz_rs, to_ssz_rs, Context as MockBuilderContext, MockBuilder,
Operation, TestingBuilder,
};
pub use mock_execution_layer::MockExecutionLayer; pub use mock_execution_layer::MockExecutionLayer;
pub const DEFAULT_TERMINAL_DIFFICULTY: u64 = 6400; pub const DEFAULT_TERMINAL_DIFFICULTY: u64 = 6400;

View File

@ -4,12 +4,16 @@ use beacon_chain::{
}; };
use eth2::types::{ use eth2::types::{
BroadcastValidation, SignedBeaconBlock, SignedBlindedBeaconBlock, SignedBlockContents, BroadcastValidation, SignedBeaconBlock, SignedBlindedBeaconBlock, SignedBlockContents,
SignedBlockContentsTuple,
}; };
use http_api::test_utils::InteractiveTester; use http_api::test_utils::InteractiveTester;
use http_api::{publish_blinded_block, publish_block, reconstruct_block, ProvenancedBlock}; use http_api::{publish_blinded_block, publish_block, reconstruct_block, ProvenancedBlock};
use std::sync::Arc; use std::sync::Arc;
use tree_hash::TreeHash; use tree_hash::TreeHash;
use types::{Hash256, MainnetEthSpec, Slot}; use types::{
BlindedBlobSidecar, BlindedPayload, BlobSidecar, FullPayload, Hash256, MainnetEthSpec,
SignedSidecarList, Slot,
};
use warp::Rejection; use warp::Rejection;
use warp_utils::reject::CustomBadRequest; use warp_utils::reject::CustomBadRequest;
@ -762,7 +766,7 @@ pub async fn blinded_gossip_invalid() {
tester.harness.advance_slot(); tester.harness.advance_slot();
let ((block, _), _): ((SignedBeaconBlock<E>, _), _) = tester let (block_contents_tuple, _) = tester
.harness .harness
.make_block_with_modifier(chain_state_before, slot, |b| { .make_block_with_modifier(chain_state_before, slot, |b| {
*b.state_root_mut() = Hash256::zero(); *b.state_root_mut() = Hash256::zero();
@ -770,11 +774,11 @@ pub async fn blinded_gossip_invalid() {
}) })
.await; .await;
let blinded_block: SignedBlindedBeaconBlock<E> = block.into(); let blinded_block_contents = into_signed_blinded_block_contents(block_contents_tuple);
let response: Result<(), eth2::Error> = tester let response: Result<(), eth2::Error> = tester
.client .client
.post_beacon_blinded_blocks_v2(&blinded_block, validation_level) .post_beacon_blinded_blocks_v2(&blinded_block_contents, validation_level)
.await; .await;
assert!(response.is_err()); assert!(response.is_err());
@ -816,18 +820,18 @@ pub async fn blinded_gossip_partial_pass() {
tester.harness.advance_slot(); tester.harness.advance_slot();
let ((block, _), _): ((SignedBeaconBlock<E>, _), _) = tester let (block_contents_tuple, _) = tester
.harness .harness
.make_block_with_modifier(chain_state_before, slot, |b| { .make_block_with_modifier(chain_state_before, slot, |b| {
*b.state_root_mut() = Hash256::zero() *b.state_root_mut() = Hash256::zero()
}) })
.await; .await;
let blinded_block: SignedBlindedBeaconBlock<E> = block.into(); let blinded_block_contents = into_signed_blinded_block_contents(block_contents_tuple);
let response: Result<(), eth2::Error> = tester let response: Result<(), eth2::Error> = tester
.client .client
.post_beacon_blinded_blocks_v2(&blinded_block, validation_level) .post_beacon_blinded_blocks_v2(&blinded_block_contents, validation_level)
.await; .await;
assert!(response.is_err()); assert!(response.is_err());
@ -864,19 +868,18 @@ pub async fn blinded_gossip_full_pass() {
let slot_b = slot_a + 1; let slot_b = slot_a + 1;
let state_a = tester.harness.get_current_state(); let state_a = tester.harness.get_current_state();
let ((block, _), _): ((SignedBlindedBeaconBlock<E>, _), _) = let (block_contents_tuple, _) = tester.harness.make_blinded_block(state_a, slot_b).await;
tester.harness.make_blinded_block(state_a, slot_b).await; let block_contents = block_contents_tuple.into();
let response: Result<(), eth2::Error> = tester let response: Result<(), eth2::Error> = tester
.client .client
.post_beacon_blinded_blocks_v2(&block, validation_level) .post_beacon_blinded_blocks_v2(&block_contents, validation_level)
.await; .await;
assert!(response.is_ok()); assert!(response.is_ok());
assert!(tester assert!(tester
.harness .harness
.chain .chain
.block_is_known_to_fork_choice(&block.canonical_root())); .block_is_known_to_fork_choice(&block_contents.signed_block().canonical_root()));
} }
// This test checks that a block that is valid from both a gossip and consensus perspective is accepted when using `broadcast_validation=gossip`. // This test checks that a block that is valid from both a gossip and consensus perspective is accepted when using `broadcast_validation=gossip`.
@ -950,7 +953,7 @@ pub async fn blinded_consensus_invalid() {
tester.harness.advance_slot(); tester.harness.advance_slot();
let ((block, _), _): ((SignedBeaconBlock<E>, _), _) = tester let (block_contents_tuple, _) = tester
.harness .harness
.make_block_with_modifier(chain_state_before, slot, |b| { .make_block_with_modifier(chain_state_before, slot, |b| {
*b.state_root_mut() = Hash256::zero(); *b.state_root_mut() = Hash256::zero();
@ -958,11 +961,11 @@ pub async fn blinded_consensus_invalid() {
}) })
.await; .await;
let blinded_block: SignedBlindedBeaconBlock<E> = block.into(); let blinded_block_contents = into_signed_blinded_block_contents(block_contents_tuple);
let response: Result<(), eth2::Error> = tester let response: Result<(), eth2::Error> = tester
.client .client
.post_beacon_blinded_blocks_v2(&blinded_block, validation_level) .post_beacon_blinded_blocks_v2(&blinded_block_contents, validation_level)
.await; .await;
assert!(response.is_err()); assert!(response.is_err());
@ -1004,16 +1007,16 @@ pub async fn blinded_consensus_gossip() {
let slot_b = slot_a + 1; let slot_b = slot_a + 1;
let state_a = tester.harness.get_current_state(); let state_a = tester.harness.get_current_state();
let ((block, _), _): ((SignedBeaconBlock<E>, _), _) = tester let (block_contents_tuple, _) = tester
.harness .harness
.make_block_with_modifier(state_a, slot_b, |b| *b.state_root_mut() = Hash256::zero()) .make_block_with_modifier(state_a, slot_b, |b| *b.state_root_mut() = Hash256::zero())
.await; .await;
let blinded_block: SignedBlindedBeaconBlock<E> = block.into(); let blinded_block_contents = into_signed_blinded_block_contents(block_contents_tuple);
let response: Result<(), eth2::Error> = tester let response: Result<(), eth2::Error> = tester
.client .client
.post_beacon_blinded_blocks_v2(&blinded_block, validation_level) .post_beacon_blinded_blocks_v2(&blinded_block_contents, validation_level)
.await; .await;
assert!(response.is_err()); assert!(response.is_err());
@ -1055,19 +1058,19 @@ pub async fn blinded_consensus_full_pass() {
let slot_b = slot_a + 1; let slot_b = slot_a + 1;
let state_a = tester.harness.get_current_state(); let state_a = tester.harness.get_current_state();
let ((block, _), _): ((SignedBlindedBeaconBlock<E>, _), _) = let (block_contents_tuple, _) = tester.harness.make_blinded_block(state_a, slot_b).await;
tester.harness.make_blinded_block(state_a, slot_b).await;
let block_contents = block_contents_tuple.into();
let response: Result<(), eth2::Error> = tester let response: Result<(), eth2::Error> = tester
.client .client
.post_beacon_blinded_blocks_v2(&block, validation_level) .post_beacon_blinded_blocks_v2(&block_contents, validation_level)
.await; .await;
assert!(response.is_ok()); assert!(response.is_ok());
assert!(tester assert!(tester
.harness .harness
.chain .chain
.block_is_known_to_fork_choice(&block.canonical_root())); .block_is_known_to_fork_choice(&block_contents.signed_block().canonical_root()));
} }
/// This test checks that a block that is **invalid** from a gossip perspective gets rejected when using `broadcast_validation=consensus_and_equivocation`. /// This test checks that a block that is **invalid** from a gossip perspective gets rejected when using `broadcast_validation=consensus_and_equivocation`.
@ -1099,7 +1102,7 @@ pub async fn blinded_equivocation_invalid() {
tester.harness.advance_slot(); tester.harness.advance_slot();
let ((block, _), _): ((SignedBeaconBlock<E>, _), _) = tester let (block_contents_tuple, _) = tester
.harness .harness
.make_block_with_modifier(chain_state_before, slot, |b| { .make_block_with_modifier(chain_state_before, slot, |b| {
*b.state_root_mut() = Hash256::zero(); *b.state_root_mut() = Hash256::zero();
@ -1107,11 +1110,11 @@ pub async fn blinded_equivocation_invalid() {
}) })
.await; .await;
let blinded_block: SignedBlindedBeaconBlock<E> = block.into(); let blinded_block_contents = into_signed_blinded_block_contents(block_contents_tuple);
let response: Result<(), eth2::Error> = tester let response: Result<(), eth2::Error> = tester
.client .client
.post_beacon_blinded_blocks_v2(&blinded_block, validation_level) .post_beacon_blinded_blocks_v2(&blinded_block_contents, validation_level)
.await; .await;
assert!(response.is_err()); assert!(response.is_err());
@ -1154,14 +1157,18 @@ pub async fn blinded_equivocation_consensus_early_equivocation() {
let slot_b = slot_a + 1; let slot_b = slot_a + 1;
let state_a = tester.harness.get_current_state(); let state_a = tester.harness.get_current_state();
let ((block_a, _), state_after_a): ((SignedBlindedBeaconBlock<E>, _), _) = tester let (block_contents_tuple_a, state_after_a) = tester
.harness .harness
.make_blinded_block(state_a.clone(), slot_b) .make_blinded_block(state_a.clone(), slot_b)
.await; .await;
let ((block_b, _), state_after_b): ((SignedBlindedBeaconBlock<E>, _), _) = let (block_contents_tuple_b, state_after_b) =
tester.harness.make_blinded_block(state_a, slot_b).await; tester.harness.make_blinded_block(state_a, slot_b).await;
/* check for `make_blinded_block` curios */ /* check for `make_blinded_block` curios */
let block_contents_a: SignedBlockContents<E, BlindedPayload<E>> = block_contents_tuple_a.into();
let block_contents_b: SignedBlockContents<E, BlindedPayload<E>> = block_contents_tuple_b.into();
let block_a = block_contents_a.signed_block();
let block_b = block_contents_b.signed_block();
assert_eq!(block_a.state_root(), state_after_a.tree_hash_root()); assert_eq!(block_a.state_root(), state_after_a.tree_hash_root());
assert_eq!(block_b.state_root(), state_after_b.tree_hash_root()); assert_eq!(block_b.state_root(), state_after_b.tree_hash_root());
assert_ne!(block_a.state_root(), block_b.state_root()); assert_ne!(block_a.state_root(), block_b.state_root());
@ -1169,7 +1176,7 @@ pub async fn blinded_equivocation_consensus_early_equivocation() {
/* submit `block_a` as valid */ /* submit `block_a` as valid */
assert!(tester assert!(tester
.client .client
.post_beacon_blinded_blocks_v2(&block_a, validation_level) .post_beacon_blinded_blocks_v2(&block_contents_a, validation_level)
.await .await
.is_ok()); .is_ok());
assert!(tester assert!(tester
@ -1180,7 +1187,7 @@ pub async fn blinded_equivocation_consensus_early_equivocation() {
/* submit `block_b` which should induce equivocation */ /* submit `block_b` which should induce equivocation */
let response: Result<(), eth2::Error> = tester let response: Result<(), eth2::Error> = tester
.client .client
.post_beacon_blinded_blocks_v2(&block_b, validation_level) .post_beacon_blinded_blocks_v2(&block_contents_b, validation_level)
.await; .await;
assert!(response.is_err()); assert!(response.is_err());
@ -1222,16 +1229,16 @@ pub async fn blinded_equivocation_gossip() {
let slot_b = slot_a + 1; let slot_b = slot_a + 1;
let state_a = tester.harness.get_current_state(); let state_a = tester.harness.get_current_state();
let ((block, _), _): ((SignedBeaconBlock<E>, _), _) = tester let (block_contents_tuple, _) = tester
.harness .harness
.make_block_with_modifier(state_a, slot_b, |b| *b.state_root_mut() = Hash256::zero()) .make_block_with_modifier(state_a, slot_b, |b| *b.state_root_mut() = Hash256::zero())
.await; .await;
let blinded_block: SignedBlindedBeaconBlock<E> = block.into(); let blinded_block_contents = into_signed_blinded_block_contents(block_contents_tuple);
let response: Result<(), eth2::Error> = tester let response: Result<(), eth2::Error> = tester
.client .client
.post_beacon_blinded_blocks_v2(&blinded_block, validation_level) .post_beacon_blinded_blocks_v2(&blinded_block_contents, validation_level)
.await; .await;
assert!(response.is_err()); assert!(response.is_err());
@ -1390,3 +1397,20 @@ pub async fn blinded_equivocation_full_pass() {
.chain .chain
.block_is_known_to_fork_choice(&block.canonical_root())); .block_is_known_to_fork_choice(&block.canonical_root()));
} }
fn into_signed_blinded_block_contents(
block_contents_tuple: SignedBlockContentsTuple<E, FullPayload<E>>,
) -> SignedBlockContents<E, BlindedPayload<E>> {
let (block, maybe_blobs) = block_contents_tuple;
SignedBlockContents::new(block.into(), maybe_blobs.map(into_blinded_blob_sidecars))
}
fn into_blinded_blob_sidecars(
blobs: SignedSidecarList<E, BlobSidecar<E>>,
) -> SignedSidecarList<E, BlindedBlobSidecar> {
blobs
.into_iter()
.map(|blob| blob.into())
.collect::<Vec<_>>()
.into()
}

View File

@ -3998,6 +3998,57 @@ impl ApiTester {
self self
} }
pub async fn test_builder_works_post_deneb(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 block_contents = self
.client
.get_validator_blinded_blocks::<E, BlindedPayload<E>>(slot, &randao_reveal, None)
.await
.unwrap()
.data;
let (block, maybe_sidecars) = block_contents.deconstruct();
// Response should contain blob sidecars
assert!(maybe_sidecars.is_some());
// The builder's payload should've been chosen, so this cache should not be populated
let payload: BlindedPayload<E> = block.body().execution_payload().unwrap().into();
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 { pub async fn test_lighthouse_rejects_invalid_withdrawals_root(self) -> Self {
// Ensure builder payload *would be* chosen // Ensure builder payload *would be* chosen
self.mock_builder self.mock_builder
@ -5112,6 +5163,25 @@ async fn builder_works_post_capella() {
.await; .await;
} }
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn builder_works_post_deneb() {
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));
config.spec.deneb_fork_epoch = Some(Epoch::new(0));
ApiTester::new_from_config(config)
.await
.test_post_validator_register_validator()
.await
.test_builder_works_post_deneb()
.await;
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)] #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn post_validator_liveness_epoch() { async fn post_validator_liveness_epoch() {
ApiTester::new() ApiTester::new()

View File

@ -17,6 +17,7 @@ use lighthouse_network::{NetworkGlobals, Request};
use slot_clock::{ManualSlotClock, SlotClock, TestingSlotClock}; use slot_clock::{ManualSlotClock, SlotClock, TestingSlotClock};
use store::MemoryStore; use store::MemoryStore;
use tokio::sync::mpsc; use tokio::sync::mpsc;
use types::beacon_block_body::to_block_kzg_commitments;
use types::{ use types::{
map_fork_name, map_fork_name_with, map_fork_name, map_fork_name_with,
test_utils::{SeedableRng, TestRandom, XorShiftRng}, test_utils::{SeedableRng, TestRandom, XorShiftRng},
@ -123,7 +124,8 @@ impl TestRig {
for tx in Vec::from(transactions) { for tx in Vec::from(transactions) {
payload.execution_payload.transactions.push(tx).unwrap(); payload.execution_payload.transactions.push(tx).unwrap();
} }
message.body.blob_kzg_commitments = bundle.commitments.clone(); message.body.blob_kzg_commitments =
to_block_kzg_commitments::<E>(bundle.commitments.clone());
let BlobsBundle { let BlobsBundle {
commitments, commitments,

View File

@ -833,17 +833,16 @@ impl BeaconNodeHttpClient {
} }
/// `POST v2/beacon/blinded_blocks` /// `POST v2/beacon/blinded_blocks`
//TODO(sean) update this along with builder updates pub async fn post_beacon_blinded_blocks_v2<T: EthSpec, Payload: AbstractExecPayload<T>>(
pub async fn post_beacon_blinded_blocks_v2<T: EthSpec>(
&self, &self,
block: &SignedBlindedBeaconBlock<T>, block_contents: &SignedBlockContents<T, Payload>,
validation_level: Option<BroadcastValidation>, validation_level: Option<BroadcastValidation>,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.post_generic_with_consensus_version( self.post_generic_with_consensus_version(
self.post_beacon_blinded_blocks_v2_path(validation_level)?, self.post_beacon_blinded_blocks_v2_path(validation_level)?,
block, block_contents,
Some(self.timeouts.proposal), Some(self.timeouts.proposal),
block.message().body().fork_name(), block_contents.signed_block().message().body().fork_name(),
) )
.await?; .await?;

View File

@ -1415,9 +1415,21 @@ impl<T: EthSpec, Payload: AbstractExecPayload<T>> ForkVersionDeserialize
D, D,
>(value, fork_name)?)) >(value, fork_name)?))
} }
ForkName::Deneb => Ok(BlockContents::BlockAndBlobSidecars( ForkName::Deneb => {
BeaconBlockAndBlobSidecars::deserialize_by_fork::<'de, D>(value, fork_name)?, let block_contents = match Payload::block_type() {
)), BlockType::Blinded => BlockContents::BlindedBlockAndBlobSidecars(
BlindedBeaconBlockAndBlobSidecars::deserialize_by_fork::<'de, D>(
value, fork_name,
)?,
),
BlockType::Full => BlockContents::BlockAndBlobSidecars(
BeaconBlockAndBlobSidecars::deserialize_by_fork::<'de, D>(
value, fork_name,
)?,
),
};
Ok(block_contents)
}
} }
} }
} }

View File

@ -9,9 +9,22 @@ use superstruct::superstruct;
use test_random_derive::TestRandom; use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash; use tree_hash_derive::TreeHash;
pub type KzgCommitments<T> = pub type KzgCommitments<T> = VariableList<KzgCommitment, <T as EthSpec>::MaxBlobsPerBlock>;
pub type BlockBodyKzgCommitments<T> =
VariableList<KzgCommitment, <T as EthSpec>::MaxBlobCommitmentsPerBlock>; VariableList<KzgCommitment, <T as EthSpec>::MaxBlobCommitmentsPerBlock>;
pub fn to_block_kzg_commitments<E: EthSpec>(
commitments: KzgCommitments<E>,
) -> BlockBodyKzgCommitments<E> {
commitments.to_vec().into()
}
pub fn from_block_kzg_commitments<E: EthSpec>(
commitments: &BlockBodyKzgCommitments<E>,
) -> KzgCommitments<E> {
commitments.to_vec().into()
}
/// The body of a `BeaconChain` block, containing operations. /// The body of a `BeaconChain` block, containing operations.
/// ///
/// This *superstruct* abstracts over the hard-fork. /// This *superstruct* abstracts over the hard-fork.
@ -72,7 +85,7 @@ pub struct BeaconBlockBody<T: EthSpec, Payload: AbstractExecPayload<T> = FullPay
pub bls_to_execution_changes: pub bls_to_execution_changes:
VariableList<SignedBlsToExecutionChange, T::MaxBlsToExecutionChanges>, VariableList<SignedBlsToExecutionChange, T::MaxBlsToExecutionChanges>,
#[superstruct(only(Deneb))] #[superstruct(only(Deneb))]
pub blob_kzg_commitments: KzgCommitments<T>, pub blob_kzg_commitments: BlockBodyKzgCommitments<T>,
#[superstruct(only(Base, Altair))] #[superstruct(only(Base, Altair))]
#[ssz(skip_serializing, skip_deserializing)] #[ssz(skip_serializing, skip_deserializing)]
#[tree_hash(skip_hashing)] #[tree_hash(skip_hashing)]

View File

@ -84,11 +84,14 @@ impl<T: EthSpec> BlobItems<T> for BlobRootsList<T> {
Ok(roots) Ok(roots)
} }
fn try_from_blobs(_blobs: BlobsList<T>) -> Result<Self, String> { fn try_from_blobs(blobs: BlobsList<T>) -> Result<Self, String> {
// It is possible to convert from blobs to blob roots, however this should be done using VariableList::new(
// `From` or `Into` instead of this generic implementation; this function implementation blobs
// should be unreachable, and attempt to use this indicates a bug somewhere. .into_iter()
Err("Unexpected conversion from blob to blob roots".to_string()) .map(|blob| blob.tree_hash_root())
.collect(),
)
.map_err(|e| format!("{e:?}"))
} }
fn len(&self) -> usize { fn len(&self) -> usize {
@ -216,6 +219,21 @@ impl<E: EthSpec> From<Arc<BlobSidecar<E>>> for BlindedBlobSidecar {
} }
} }
impl<E: EthSpec> From<BlobSidecar<E>> for BlindedBlobSidecar {
fn from(blob_sidecar: BlobSidecar<E>) -> Self {
BlindedBlobSidecar {
block_root: blob_sidecar.block_root,
index: blob_sidecar.index,
slot: blob_sidecar.slot,
block_parent_root: blob_sidecar.block_parent_root,
proposer_index: blob_sidecar.proposer_index,
blob_root: blob_sidecar.blob.tree_hash_root(),
kzg_commitment: blob_sidecar.kzg_commitment,
kzg_proof: blob_sidecar.kzg_proof,
}
}
}
impl<T: EthSpec> PartialOrd for BlobSidecar<T> { impl<T: EthSpec> PartialOrd for BlobSidecar<T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.index.partial_cmp(&other.index) self.index.partial_cmp(&other.index)

View File

@ -1,17 +1,19 @@
use crate::beacon_block_body::KzgCommitments; use crate::beacon_block_body::KzgCommitments;
use crate::{ use crate::{
BlobRootsList, ChainSpec, EthSpec, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb, BlobRootsList, BlobsBundle, ChainSpec, EthSpec, ExecutionPayloadHeaderCapella,
ExecutionPayloadHeaderMerge, ExecutionPayloadHeaderRef, ForkName, ForkVersionDeserialize, ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderMerge, ExecutionPayloadHeaderRef, ForkName,
KzgProofs, SignedRoot, Uint256, ForkVersionDeserialize, KzgProofs, SignedRoot, Uint256,
}; };
use bls::PublicKeyBytes; use bls::PublicKeyBytes;
use bls::Signature; use bls::Signature;
use serde::Deserializer; use serde::Deserializer;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use ssz_derive::Encode;
use superstruct::superstruct; use superstruct::superstruct;
use tree_hash::TreeHash;
use tree_hash_derive::TreeHash; use tree_hash_derive::TreeHash;
#[derive(PartialEq, Debug, Serialize, Deserialize, TreeHash, Clone)] #[derive(PartialEq, Debug, Default, Serialize, Deserialize, TreeHash, Clone, Encode)]
#[serde(bound = "E: EthSpec")] #[serde(bound = "E: EthSpec")]
pub struct BlindedBlobsBundle<E: EthSpec> { pub struct BlindedBlobsBundle<E: EthSpec> {
pub commitments: KzgCommitments<E>, pub commitments: KzgCommitments<E>,
@ -19,6 +21,21 @@ pub struct BlindedBlobsBundle<E: EthSpec> {
pub blob_roots: BlobRootsList<E>, pub blob_roots: BlobRootsList<E>,
} }
impl<E: EthSpec> From<BlobsBundle<E>> for BlindedBlobsBundle<E> {
fn from(blobs_bundle: BlobsBundle<E>) -> Self {
BlindedBlobsBundle {
commitments: blobs_bundle.commitments,
proofs: blobs_bundle.proofs,
blob_roots: blobs_bundle
.blobs
.into_iter()
.map(|blob| blob.tree_hash_root())
.collect::<Vec<_>>()
.into(),
}
}
}
#[superstruct( #[superstruct(
variants(Merge, Capella, Deneb), variants(Merge, Capella, Deneb),
variant_attributes( variant_attributes(

View File

@ -972,9 +972,10 @@ impl<T: EthSpec> From<BlindedPayload<T>> for ExecutionPayloadHeader<T> {
} }
} }
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Encode)]
#[serde(untagged)] #[serde(untagged)]
#[serde(bound = "E: EthSpec")] #[serde(bound = "E: EthSpec")]
#[ssz(enum_behaviour = "transparent")]
pub enum FullPayloadContents<E: EthSpec> { pub enum FullPayloadContents<E: EthSpec> {
Payload(ExecutionPayload<E>), Payload(ExecutionPayload<E>),
PayloadAndBlobs(ExecutionPayloadAndBlobs<E>), PayloadAndBlobs(ExecutionPayloadAndBlobs<E>),
@ -1037,14 +1038,14 @@ impl<E: EthSpec> ForkVersionDeserialize for FullPayloadContents<E> {
} }
} }
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Encode)]
#[serde(bound = "E: EthSpec")] #[serde(bound = "E: EthSpec")]
pub struct ExecutionPayloadAndBlobs<E: EthSpec> { pub struct ExecutionPayloadAndBlobs<E: EthSpec> {
pub execution_payload: ExecutionPayload<E>, pub execution_payload: ExecutionPayload<E>,
pub blobs_bundle: BlobsBundle<E>, pub blobs_bundle: BlobsBundle<E>,
} }
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, Encode)]
#[serde(bound = "E: EthSpec")] #[serde(bound = "E: EthSpec")]
pub struct BlobsBundle<E: EthSpec> { pub struct BlobsBundle<E: EthSpec> {
pub commitments: KzgCommitments<E>, pub commitments: KzgCommitments<E>,

View File

@ -59,13 +59,6 @@ impl<T: EthSpec> SignedSidecar<T, BlindedBlobSidecar> {
} }
} }
/// List of Signed Sidecars that implements `Sidecar`.
pub type SignedSidecarList<T, Sidecar> =
VariableList<SignedSidecar<T, Sidecar>, <T as EthSpec>::MaxBlobsPerBlock>;
pub type SignedBlobSidecarList<T> = SignedSidecarList<T, BlobSidecar<T>>;
pub type SignedBlobSidecar<T> = SignedSidecar<T, BlobSidecar<T>>;
impl<T: EthSpec> SignedBlobSidecar<T> { impl<T: EthSpec> SignedBlobSidecar<T> {
/// Verify `self.signature`. /// Verify `self.signature`.
/// ///
@ -99,3 +92,21 @@ impl<T: EthSpec> SignedBlobSidecar<T> {
self.signature.verify(pubkey, message) self.signature.verify(pubkey, message)
} }
} }
impl<T: EthSpec> From<SignedBlobSidecar<T>> for SignedBlindedBlobSidecar<T> {
fn from(signed: SignedBlobSidecar<T>) -> Self {
SignedBlindedBlobSidecar {
message: Arc::new(signed.message.into()),
signature: signed.signature,
_phantom: PhantomData,
}
}
}
pub type SignedBlobSidecar<T> = SignedSidecar<T, BlobSidecar<T>>;
pub type SignedBlindedBlobSidecar<T> = SignedSidecar<T, BlindedBlobSidecar>;
/// List of Signed Sidecars that implements `Sidecar`.
pub type SignedSidecarList<T, Sidecar> =
VariableList<SignedSidecar<T, Sidecar>, <T as EthSpec>::MaxBlobsPerBlock>;
pub type SignedBlobSidecarList<T> = SignedSidecarList<T, BlobSidecar<T>>;

View File

@ -13,7 +13,7 @@
"londonBlock": 0, "londonBlock": 0,
"mergeNetsplitBlock": 0, "mergeNetsplitBlock": 0,
"shanghaiTime": 0, "shanghaiTime": 0,
"shardingForkTime": 0, "cancunTime": 0,
"terminalTotalDifficulty": 0, "terminalTotalDifficulty": 0,
"terminalTotalDifficultyPassed": true "terminalTotalDifficultyPassed": true
}, },

View File

@ -110,7 +110,7 @@ echo $CAPELLA_TIME
sed -i 's/"shanghaiTime".*$/"shanghaiTime": '"$CAPELLA_TIME"',/g' $genesis_file sed -i 's/"shanghaiTime".*$/"shanghaiTime": '"$CAPELLA_TIME"',/g' $genesis_file
CANCUN_TIME=$((GENESIS_TIME + (DENEB_FORK_EPOCH * 32 * SECONDS_PER_SLOT))) CANCUN_TIME=$((GENESIS_TIME + (DENEB_FORK_EPOCH * 32 * SECONDS_PER_SLOT)))
echo $CANCUN_TIME echo $CANCUN_TIME
sed -i 's/"shardingForkTime".*$/"shardingForkTime": '"$CANCUN_TIME"',/g' $genesis_file sed -i 's/"cancunTime".*$/"cancunTime": '"$CANCUN_TIME"',/g' $genesis_file
cat $genesis_file cat $genesis_file
# Delay to let boot_enr.yaml to be created # Delay to let boot_enr.yaml to be created
@ -141,7 +141,7 @@ sleeping 20
# Reset the `genesis.json` config file fork times. # Reset the `genesis.json` config file fork times.
sed -i 's/"shanghaiTime".*$/"shanghaiTime": 0,/g' $genesis_file sed -i 's/"shanghaiTime".*$/"shanghaiTime": 0,/g' $genesis_file
sed -i 's/"shardingForkTime".*$/"shardingForkTime": 0,/g' $genesis_file sed -i 's/"cancunTime".*$/"cancunTime": 0,/g' $genesis_file
for (( bn=1; bn<=$BN_COUNT; bn++ )); do for (( bn=1; bn<=$BN_COUNT; bn++ )); do
secret=$DATADIR/geth_datadir$bn/geth/jwtsecret secret=$DATADIR/geth_datadir$bn/geth/jwtsecret