diff --git a/Cargo.lock b/Cargo.lock index 5f0835f9f..b1369d21f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,7 +18,7 @@ version = "0.3.5" dependencies = [ "account_utils", "bls", - "clap", + "clap 2.34.0", "clap_utils", "directory", "environment", @@ -183,6 +183,55 @@ dependencies = [ "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]] name = "anvil-rpc" version = "0.1.0" @@ -479,8 +528,9 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "beacon-api-client" 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 = [ + "clap 4.3.21", "ethereum-consensus", "http", "itertools", @@ -562,7 +612,7 @@ name = "beacon_node" version = "4.3.0" dependencies = [ "beacon_chain", - "clap", + "clap 2.34.0", "clap_utils", "client", "directory", @@ -785,7 +835,7 @@ name = "boot_node" version = "4.3.0" dependencies = [ "beacon_node", - "clap", + "clap 2.34.0", "clap_utils", "eth2_network_config", "ethereum_ssz", @@ -1067,11 +1117,52 @@ dependencies = [ "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]] name = "clap_utils" version = "0.1.0" dependencies = [ - "clap", + "clap 2.34.0", "dirs", "eth2_network_config", "ethereum-types 0.14.1", @@ -1135,6 +1226,12 @@ dependencies = [ "cc", ] +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + [[package]] name = "compare_fields" version = "0.2.0" @@ -1222,7 +1319,7 @@ checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" dependencies = [ "atty", "cast", - "clap", + "clap 2.34.0", "criterion-plot", "csv", "itertools", @@ -1508,7 +1605,7 @@ version = "0.1.0" dependencies = [ "beacon_chain", "beacon_node", - "clap", + "clap 2.34.0", "clap_utils", "environment", "logging", @@ -1683,7 +1780,7 @@ dependencies = [ name = "directory" version = "0.1.0" dependencies = [ - "clap", + "clap 2.34.0", "clap_utils", "eth2_network_config", ] @@ -2317,7 +2414,7 @@ dependencies = [ [[package]] name = "ethereum-consensus" 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 = [ "async-stream", "blst", @@ -3724,6 +3821,17 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "itertools" version = "0.10.5" @@ -3879,7 +3987,7 @@ dependencies = [ "account_utils", "beacon_chain", "bls", - "clap", + "clap 2.34.0", "clap_utils", "deposit_contract", "directory", @@ -4433,7 +4541,7 @@ dependencies = [ "beacon_processor", "bls", "boot_node", - "clap", + "clap 2.34.0", "clap_utils", "database_manager", "directory", @@ -4799,7 +4907,7 @@ dependencies = [ [[package]] name = "mev-rs" 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 = [ "anvil-rpc", "async-trait", @@ -7147,7 +7255,7 @@ dependencies = [ name = "simulator" version = "0.2.0" dependencies = [ - "clap", + "clap 2.34.0", "env_logger 0.9.3", "eth1", "eth1_test_rig", @@ -8659,6 +8767,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "uuid" version = "0.8.2" @@ -8676,7 +8790,7 @@ dependencies = [ "account_utils", "bincode", "bls", - "clap", + "clap 2.34.0", "clap_utils", "deposit_contract", "directory", @@ -8749,7 +8863,7 @@ version = "0.1.0" dependencies = [ "account_utils", "bls", - "clap", + "clap 2.34.0", "clap_utils", "environment", "eth2", @@ -8992,7 +9106,7 @@ dependencies = [ "beacon_node", "bls", "byteorder", - "clap", + "clap 2.34.0", "diesel", "diesel_migrations", "env_logger 0.9.3", diff --git a/Cargo.toml b/Cargo.toml index 02f0becbb..2450212c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -94,6 +94,10 @@ resolver = "2" [patch.crates-io] 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] inherits = "release" lto = "fat" diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 6f0e66112..e788ac815 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -118,6 +118,7 @@ use store::{ use task_executor::{ShutdownReason, TaskExecutor}; use tokio_stream::Stream; use tree_hash::TreeHash; +use types::beacon_block_body::{from_block_kzg_commitments, to_block_kzg_commitments}; use types::beacon_state::CloneConfig; use types::blob_sidecar::{BlobItems, BlobSidecarList, FixedBlobSidecarList}; use types::consts::deneb::MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS; @@ -4925,6 +4926,7 @@ impl BeaconChain { .map_err(|_| BlockProductionError::InvalidPayloadFork)?, bls_to_execution_changes: bls_to_execution_changes.into(), blob_kzg_commitments: kzg_commitments + .map(to_block_kzg_commitments::) .ok_or(BlockProductionError::InvalidPayloadFork)?, }, }), @@ -4984,8 +4986,11 @@ impl BeaconChain { metrics::start_timer(&metrics::BLOCK_PRODUCTION_BLOBS_VERIFICATION_TIMES); let maybe_sidecar_list = match (blobs_opt, proofs_opt) { (Some(blobs_or_blobs_roots), Some(proofs)) => { - let expected_kzg_commitments = - block.body().blob_kzg_commitments().map_err(|_| { + let expected_kzg_commitments = block + .body() + .blob_kzg_commitments() + .map(from_block_kzg_commitments::) + .map_err(|_| { BlockProductionError::InvalidBlockVariant( "deneb block does not contain kzg commitments".to_string(), ) @@ -5009,7 +5014,7 @@ impl BeaconChain { .ok_or(BlockProductionError::TrustedSetupNotInitialized)?; kzg_utils::validate_blobs::( kzg, - expected_kzg_commitments, + &expected_kzg_commitments, blobs, &kzg_proofs, ) @@ -5020,7 +5025,7 @@ impl BeaconChain { Sidecar::build_sidecar( blobs_or_blobs_roots, &block, - expected_kzg_commitments, + &expected_kzg_commitments, kzg_proofs, ) .map_err(BlockProductionError::FailedToBuildBlobSidecars)?, diff --git a/beacon_node/execution_layer/Cargo.toml b/beacon_node/execution_layer/Cargo.toml index 11a2c2012..89ad9915f 100644 --- a/beacon_node/execution_layer/Cargo.toml +++ b/beacon_node/execution_layer/Cargo.toml @@ -42,8 +42,8 @@ lazy_static = "1.4.0" ethers-core = "1.0.2" builder_client = { path = "../builder_client" } fork_choice = { path = "../../consensus/fork_choice" } -mev-rs = { git = "https://github.com/ralexstokes/mev-rs", rev = "216657016d5c0889b505857c89ae42c7aa2764af" } -ethereum-consensus = { git = "https://github.com/ralexstokes/ethereum-consensus", rev = "e380108" } +mev-rs = { git = "https://github.com/ralexstokes/mev-rs", rev = "9d88a2386b58c2948fa850f0dd4b3dfe18bd4962" } +ethereum-consensus = { git = "https://github.com/ralexstokes/ethereum-consensus", rev = "56418ea" } ssz_rs = "0.9.0" tokio-stream = { version = "0.1.9", features = [ "sync" ] } strum = "0.24.0" diff --git a/beacon_node/execution_layer/src/test_utils/mock_builder.rs b/beacon_node/execution_layer/src/test_utils/mock_builder.rs index cd29a998b..4c62e84ab 100644 --- a/beacon_node/execution_layer/src/test_utils/mock_builder.rs +++ b/beacon_node/execution_layer/src/test_utils/mock_builder.rs @@ -18,6 +18,7 @@ use mev_rs::{ BuilderBid as BuilderBidBellatrix, SignedBuilderBid as SignedBuilderBidBellatrix, }, capella::{BuilderBid as BuilderBidCapella, SignedBuilderBid as SignedBuilderBidCapella}, + deneb::{BuilderBid as BuilderBidDeneb, SignedBuilderBid as SignedBuilderBidDeneb}, BidRequest, BuilderBid, ExecutionPayload as ServerPayload, SignedBlindedBeaconBlock, SignedBuilderBid, SignedValidatorRegistration, }, @@ -35,8 +36,9 @@ use std::time::Duration; use task_executor::TaskExecutor; use tempfile::NamedTempFile; use tree_hash::TreeHash; +use types::builder_bid::BlindedBlobsBundle; use types::{ - Address, BeaconState, ChainSpec, EthSpec, ExecPayload, ExecutionPayload, + Address, BeaconState, BlobsBundle, ChainSpec, EthSpec, ExecPayload, ExecutionPayload, ExecutionPayloadHeader, ForkName, Hash256, Slot, Uint256, }; @@ -90,60 +92,50 @@ pub trait BidStuff { 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 { 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, - } + map_builder_bid!(self, |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, - } + map_builder_bid!(self, |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, - } + map_builder_bid!(self, |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, - } + map_builder_bid!(self, |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, - } + map_builder_bid!(self, |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, - } + map_builder_bid!(self, |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, - } + map_builder_bid!(self, |bid| &mut bid.header.timestamp) } fn withdrawals_root_mut(&mut self) -> Result<&mut Root, MevError> { match self { Self::Bellatrix(_) => Err(MevError::InvalidFork), 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, context: &Context, ) -> Result { - match self { - Self::Bellatrix(message) => sign_builder_message(message, signing_key, context), - Self::Capella(message) => sign_builder_message(message, signing_key, context), - } + map_builder_bid!(self, |message| sign_builder_message( + message, + signing_key, + context + )) } fn to_signed_bid(self, signature: Signature) -> SignedBuilderBid { @@ -166,6 +159,9 @@ impl BidStuff for BuilderBid { Self::Capella(message) => { SignedBuilderBid::Capella(SignedBuilderBidCapella { message, signature }) } + Self::Deneb(message) => { + SignedBuilderBid::Deneb(SignedBuilderBidDeneb { message, signature }) + } } } } @@ -285,6 +281,10 @@ impl MockBuilder { } Ok(()) } + + pub fn pubkey(&self) -> ethereum_consensus::crypto::PublicKey { + self.builder_sk.public_key() + } } #[async_trait] @@ -435,7 +435,11 @@ impl mev_rs::BlindedBlockProvider for MockBuilder { finalized_hash: Some(finalized_execution_hash), }; - let payload: ExecutionPayload = self + let (payload, _block_value, maybe_blobs_bundle): ( + ExecutionPayload, + Uint256, + Option>, + ) = self .el .get_full_payload_caching( head_execution_hash, @@ -455,21 +459,28 @@ impl mev_rs::BlindedBlockProvider for MockBuilder { ExecutionPayload::Deneb(payload) => ExecutionPayloadHeader::Deneb((&payload).into()), }; - let json_payload = serde_json::to_string(&header).map_err(convert_err)?; let mut message = match fork { + ForkName::Deneb => { + let blinded_blobs: BlindedBlobsBundle = + 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 { - 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))?, 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)?, + header: to_ssz_rs(&header)?, value: to_ssz_rs(&Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI))?, public_key: self.builder_sk.public_key(), }), - ForkName::Base | ForkName::Altair | ForkName::Deneb => { - return Err(MevError::InvalidFork) - } + ForkName::Base | ForkName::Altair => return Err(MevError::InvalidFork), }; *message.gas_limit_mut() = cached_data.gas_limit; @@ -495,6 +506,12 @@ impl mev_rs::BlindedBlockProvider for MockBuilder { SignedBlindedBeaconBlock::Capella(block) => { 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)?; @@ -521,12 +538,12 @@ pub fn to_ssz_rs(ssz_data: &T) -> Result(&ssz_data.as_ssz_bytes()).map_err(convert_err) } -fn convert_err(e: E) -> MevError { +pub fn convert_err(e: E) -> MevError { custom_err(format!("{e:?}")) } // 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( std::io::Error::new(std::io::ErrorKind::Other, s), )) diff --git a/beacon_node/execution_layer/src/test_utils/mod.rs b/beacon_node/execution_layer/src/test_utils/mod.rs index 95abbdbc9..0366d682c 100644 --- a/beacon_node/execution_layer/src/test_utils/mod.rs +++ b/beacon_node/execution_layer/src/test_utils/mod.rs @@ -29,7 +29,10 @@ pub use execution_block_generator::{ Block, ExecutionBlockGenerator, }; 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 const DEFAULT_TERMINAL_DIFFICULTY: u64 = 6400; diff --git a/beacon_node/http_api/tests/broadcast_validation_tests.rs b/beacon_node/http_api/tests/broadcast_validation_tests.rs index d6287038e..9f032cb13 100644 --- a/beacon_node/http_api/tests/broadcast_validation_tests.rs +++ b/beacon_node/http_api/tests/broadcast_validation_tests.rs @@ -4,12 +4,16 @@ use beacon_chain::{ }; use eth2::types::{ BroadcastValidation, SignedBeaconBlock, SignedBlindedBeaconBlock, SignedBlockContents, + SignedBlockContentsTuple, }; use http_api::test_utils::InteractiveTester; use http_api::{publish_blinded_block, publish_block, reconstruct_block, ProvenancedBlock}; use std::sync::Arc; use tree_hash::TreeHash; -use types::{Hash256, MainnetEthSpec, Slot}; +use types::{ + BlindedBlobSidecar, BlindedPayload, BlobSidecar, FullPayload, Hash256, MainnetEthSpec, + SignedSidecarList, Slot, +}; use warp::Rejection; use warp_utils::reject::CustomBadRequest; @@ -762,7 +766,7 @@ pub async fn blinded_gossip_invalid() { tester.harness.advance_slot(); - let ((block, _), _): ((SignedBeaconBlock, _), _) = tester + let (block_contents_tuple, _) = tester .harness .make_block_with_modifier(chain_state_before, slot, |b| { *b.state_root_mut() = Hash256::zero(); @@ -770,11 +774,11 @@ pub async fn blinded_gossip_invalid() { }) .await; - let blinded_block: SignedBlindedBeaconBlock = block.into(); + let blinded_block_contents = into_signed_blinded_block_contents(block_contents_tuple); let response: Result<(), eth2::Error> = tester .client - .post_beacon_blinded_blocks_v2(&blinded_block, validation_level) + .post_beacon_blinded_blocks_v2(&blinded_block_contents, validation_level) .await; assert!(response.is_err()); @@ -816,18 +820,18 @@ pub async fn blinded_gossip_partial_pass() { tester.harness.advance_slot(); - let ((block, _), _): ((SignedBeaconBlock, _), _) = tester + let (block_contents_tuple, _) = tester .harness .make_block_with_modifier(chain_state_before, slot, |b| { *b.state_root_mut() = Hash256::zero() }) .await; - let blinded_block: SignedBlindedBeaconBlock = block.into(); + let blinded_block_contents = into_signed_blinded_block_contents(block_contents_tuple); let response: Result<(), eth2::Error> = tester .client - .post_beacon_blinded_blocks_v2(&blinded_block, validation_level) + .post_beacon_blinded_blocks_v2(&blinded_block_contents, validation_level) .await; assert!(response.is_err()); @@ -864,19 +868,18 @@ pub async fn blinded_gossip_full_pass() { let slot_b = slot_a + 1; let state_a = tester.harness.get_current_state(); - let ((block, _), _): ((SignedBlindedBeaconBlock, _), _) = - tester.harness.make_blinded_block(state_a, slot_b).await; - + let (block_contents_tuple, _) = tester.harness.make_blinded_block(state_a, slot_b).await; + let block_contents = block_contents_tuple.into(); let response: Result<(), eth2::Error> = tester .client - .post_beacon_blinded_blocks_v2(&block, validation_level) + .post_beacon_blinded_blocks_v2(&block_contents, validation_level) .await; assert!(response.is_ok()); assert!(tester .harness .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`. @@ -950,7 +953,7 @@ pub async fn blinded_consensus_invalid() { tester.harness.advance_slot(); - let ((block, _), _): ((SignedBeaconBlock, _), _) = tester + let (block_contents_tuple, _) = tester .harness .make_block_with_modifier(chain_state_before, slot, |b| { *b.state_root_mut() = Hash256::zero(); @@ -958,11 +961,11 @@ pub async fn blinded_consensus_invalid() { }) .await; - let blinded_block: SignedBlindedBeaconBlock = block.into(); + let blinded_block_contents = into_signed_blinded_block_contents(block_contents_tuple); let response: Result<(), eth2::Error> = tester .client - .post_beacon_blinded_blocks_v2(&blinded_block, validation_level) + .post_beacon_blinded_blocks_v2(&blinded_block_contents, validation_level) .await; assert!(response.is_err()); @@ -1004,16 +1007,16 @@ pub async fn blinded_consensus_gossip() { let slot_b = slot_a + 1; let state_a = tester.harness.get_current_state(); - let ((block, _), _): ((SignedBeaconBlock, _), _) = tester + let (block_contents_tuple, _) = tester .harness .make_block_with_modifier(state_a, slot_b, |b| *b.state_root_mut() = Hash256::zero()) .await; - let blinded_block: SignedBlindedBeaconBlock = block.into(); + let blinded_block_contents = into_signed_blinded_block_contents(block_contents_tuple); let response: Result<(), eth2::Error> = tester .client - .post_beacon_blinded_blocks_v2(&blinded_block, validation_level) + .post_beacon_blinded_blocks_v2(&blinded_block_contents, validation_level) .await; assert!(response.is_err()); @@ -1055,19 +1058,19 @@ pub async fn blinded_consensus_full_pass() { let slot_b = slot_a + 1; let state_a = tester.harness.get_current_state(); - let ((block, _), _): ((SignedBlindedBeaconBlock, _), _) = - tester.harness.make_blinded_block(state_a, slot_b).await; + let (block_contents_tuple, _) = tester.harness.make_blinded_block(state_a, slot_b).await; + let block_contents = block_contents_tuple.into(); let response: Result<(), eth2::Error> = tester .client - .post_beacon_blinded_blocks_v2(&block, validation_level) + .post_beacon_blinded_blocks_v2(&block_contents, validation_level) .await; assert!(response.is_ok()); assert!(tester .harness .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`. @@ -1099,7 +1102,7 @@ pub async fn blinded_equivocation_invalid() { tester.harness.advance_slot(); - let ((block, _), _): ((SignedBeaconBlock, _), _) = tester + let (block_contents_tuple, _) = tester .harness .make_block_with_modifier(chain_state_before, slot, |b| { *b.state_root_mut() = Hash256::zero(); @@ -1107,11 +1110,11 @@ pub async fn blinded_equivocation_invalid() { }) .await; - let blinded_block: SignedBlindedBeaconBlock = block.into(); + let blinded_block_contents = into_signed_blinded_block_contents(block_contents_tuple); let response: Result<(), eth2::Error> = tester .client - .post_beacon_blinded_blocks_v2(&blinded_block, validation_level) + .post_beacon_blinded_blocks_v2(&blinded_block_contents, validation_level) .await; assert!(response.is_err()); @@ -1154,14 +1157,18 @@ pub async fn blinded_equivocation_consensus_early_equivocation() { let slot_b = slot_a + 1; let state_a = tester.harness.get_current_state(); - let ((block_a, _), state_after_a): ((SignedBlindedBeaconBlock, _), _) = tester + let (block_contents_tuple_a, state_after_a) = tester .harness .make_blinded_block(state_a.clone(), slot_b) .await; - let ((block_b, _), state_after_b): ((SignedBlindedBeaconBlock, _), _) = + let (block_contents_tuple_b, state_after_b) = tester.harness.make_blinded_block(state_a, slot_b).await; /* check for `make_blinded_block` curios */ + let block_contents_a: SignedBlockContents> = block_contents_tuple_a.into(); + let block_contents_b: SignedBlockContents> = 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_b.state_root(), state_after_b.tree_hash_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 */ assert!(tester .client - .post_beacon_blinded_blocks_v2(&block_a, validation_level) + .post_beacon_blinded_blocks_v2(&block_contents_a, validation_level) .await .is_ok()); assert!(tester @@ -1180,7 +1187,7 @@ pub async fn blinded_equivocation_consensus_early_equivocation() { /* submit `block_b` which should induce equivocation */ let response: Result<(), eth2::Error> = tester .client - .post_beacon_blinded_blocks_v2(&block_b, validation_level) + .post_beacon_blinded_blocks_v2(&block_contents_b, validation_level) .await; assert!(response.is_err()); @@ -1222,16 +1229,16 @@ pub async fn blinded_equivocation_gossip() { let slot_b = slot_a + 1; let state_a = tester.harness.get_current_state(); - let ((block, _), _): ((SignedBeaconBlock, _), _) = tester + let (block_contents_tuple, _) = tester .harness .make_block_with_modifier(state_a, slot_b, |b| *b.state_root_mut() = Hash256::zero()) .await; - let blinded_block: SignedBlindedBeaconBlock = block.into(); + let blinded_block_contents = into_signed_blinded_block_contents(block_contents_tuple); let response: Result<(), eth2::Error> = tester .client - .post_beacon_blinded_blocks_v2(&blinded_block, validation_level) + .post_beacon_blinded_blocks_v2(&blinded_block_contents, validation_level) .await; assert!(response.is_err()); @@ -1390,3 +1397,20 @@ pub async fn blinded_equivocation_full_pass() { .chain .block_is_known_to_fork_choice(&block.canonical_root())); } + +fn into_signed_blinded_block_contents( + block_contents_tuple: SignedBlockContentsTuple>, +) -> SignedBlockContents> { + 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>, +) -> SignedSidecarList { + blobs + .into_iter() + .map(|blob| blob.into()) + .collect::>() + .into() +} diff --git a/beacon_node/http_api/tests/tests.rs b/beacon_node/http_api/tests/tests.rs index de2cd4aea..f89a5c244 100644 --- a/beacon_node/http_api/tests/tests.rs +++ b/beacon_node/http_api/tests/tests.rs @@ -3998,6 +3998,57 @@ impl ApiTester { 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::>(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 = 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 { // Ensure builder payload *would be* chosen self.mock_builder @@ -5112,6 +5163,25 @@ async fn builder_works_post_capella() { .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)] async fn post_validator_liveness_epoch() { ApiTester::new() diff --git a/beacon_node/network/src/sync/block_lookups/tests.rs b/beacon_node/network/src/sync/block_lookups/tests.rs index 5793adfbb..660e693d2 100644 --- a/beacon_node/network/src/sync/block_lookups/tests.rs +++ b/beacon_node/network/src/sync/block_lookups/tests.rs @@ -17,6 +17,7 @@ use lighthouse_network::{NetworkGlobals, Request}; use slot_clock::{ManualSlotClock, SlotClock, TestingSlotClock}; use store::MemoryStore; use tokio::sync::mpsc; +use types::beacon_block_body::to_block_kzg_commitments; use types::{ map_fork_name, map_fork_name_with, test_utils::{SeedableRng, TestRandom, XorShiftRng}, @@ -123,7 +124,8 @@ impl TestRig { for tx in Vec::from(transactions) { payload.execution_payload.transactions.push(tx).unwrap(); } - message.body.blob_kzg_commitments = bundle.commitments.clone(); + message.body.blob_kzg_commitments = + to_block_kzg_commitments::(bundle.commitments.clone()); let BlobsBundle { commitments, diff --git a/common/eth2/src/lib.rs b/common/eth2/src/lib.rs index 7c9a8a23b..a0fc9c3f2 100644 --- a/common/eth2/src/lib.rs +++ b/common/eth2/src/lib.rs @@ -833,17 +833,16 @@ impl BeaconNodeHttpClient { } /// `POST v2/beacon/blinded_blocks` - //TODO(sean) update this along with builder updates - pub async fn post_beacon_blinded_blocks_v2( + pub async fn post_beacon_blinded_blocks_v2>( &self, - block: &SignedBlindedBeaconBlock, + block_contents: &SignedBlockContents, validation_level: Option, ) -> Result<(), Error> { self.post_generic_with_consensus_version( self.post_beacon_blinded_blocks_v2_path(validation_level)?, - block, + block_contents, Some(self.timeouts.proposal), - block.message().body().fork_name(), + block_contents.signed_block().message().body().fork_name(), ) .await?; diff --git a/common/eth2/src/types.rs b/common/eth2/src/types.rs index a10e7b224..0a61d075d 100644 --- a/common/eth2/src/types.rs +++ b/common/eth2/src/types.rs @@ -1415,9 +1415,21 @@ impl> ForkVersionDeserialize D, >(value, fork_name)?)) } - ForkName::Deneb => Ok(BlockContents::BlockAndBlobSidecars( - BeaconBlockAndBlobSidecars::deserialize_by_fork::<'de, D>(value, fork_name)?, - )), + ForkName::Deneb => { + 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) + } } } } diff --git a/consensus/types/src/beacon_block_body.rs b/consensus/types/src/beacon_block_body.rs index 61400a8b4..6c31e8cc1 100644 --- a/consensus/types/src/beacon_block_body.rs +++ b/consensus/types/src/beacon_block_body.rs @@ -9,9 +9,22 @@ use superstruct::superstruct; use test_random_derive::TestRandom; use tree_hash_derive::TreeHash; -pub type KzgCommitments = +pub type KzgCommitments = VariableList::MaxBlobsPerBlock>; +pub type BlockBodyKzgCommitments = VariableList::MaxBlobCommitmentsPerBlock>; +pub fn to_block_kzg_commitments( + commitments: KzgCommitments, +) -> BlockBodyKzgCommitments { + commitments.to_vec().into() +} + +pub fn from_block_kzg_commitments( + commitments: &BlockBodyKzgCommitments, +) -> KzgCommitments { + commitments.to_vec().into() +} + /// The body of a `BeaconChain` block, containing operations. /// /// This *superstruct* abstracts over the hard-fork. @@ -72,7 +85,7 @@ pub struct BeaconBlockBody = FullPay pub bls_to_execution_changes: VariableList, #[superstruct(only(Deneb))] - pub blob_kzg_commitments: KzgCommitments, + pub blob_kzg_commitments: BlockBodyKzgCommitments, #[superstruct(only(Base, Altair))] #[ssz(skip_serializing, skip_deserializing)] #[tree_hash(skip_hashing)] diff --git a/consensus/types/src/blob_sidecar.rs b/consensus/types/src/blob_sidecar.rs index b51cc0f32..4e29e7cd6 100644 --- a/consensus/types/src/blob_sidecar.rs +++ b/consensus/types/src/blob_sidecar.rs @@ -84,11 +84,14 @@ impl BlobItems for BlobRootsList { Ok(roots) } - fn try_from_blobs(_blobs: BlobsList) -> Result { - // It is possible to convert from blobs to blob roots, however this should be done using - // `From` or `Into` instead of this generic implementation; this function implementation - // should be unreachable, and attempt to use this indicates a bug somewhere. - Err("Unexpected conversion from blob to blob roots".to_string()) + fn try_from_blobs(blobs: BlobsList) -> Result { + VariableList::new( + blobs + .into_iter() + .map(|blob| blob.tree_hash_root()) + .collect(), + ) + .map_err(|e| format!("{e:?}")) } fn len(&self) -> usize { @@ -216,6 +219,21 @@ impl From>> for BlindedBlobSidecar { } } +impl From> for BlindedBlobSidecar { + fn from(blob_sidecar: BlobSidecar) -> 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 PartialOrd for BlobSidecar { fn partial_cmp(&self, other: &Self) -> Option { self.index.partial_cmp(&other.index) diff --git a/consensus/types/src/builder_bid.rs b/consensus/types/src/builder_bid.rs index e0c0bb306..bc358dc17 100644 --- a/consensus/types/src/builder_bid.rs +++ b/consensus/types/src/builder_bid.rs @@ -1,17 +1,19 @@ use crate::beacon_block_body::KzgCommitments; use crate::{ - BlobRootsList, ChainSpec, EthSpec, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb, - ExecutionPayloadHeaderMerge, ExecutionPayloadHeaderRef, ForkName, ForkVersionDeserialize, - KzgProofs, SignedRoot, Uint256, + BlobRootsList, BlobsBundle, ChainSpec, EthSpec, ExecutionPayloadHeaderCapella, + ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderMerge, ExecutionPayloadHeaderRef, ForkName, + ForkVersionDeserialize, KzgProofs, SignedRoot, Uint256, }; use bls::PublicKeyBytes; use bls::Signature; use serde::Deserializer; use serde_derive::{Deserialize, Serialize}; +use ssz_derive::Encode; use superstruct::superstruct; +use tree_hash::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")] pub struct BlindedBlobsBundle { pub commitments: KzgCommitments, @@ -19,6 +21,21 @@ pub struct BlindedBlobsBundle { pub blob_roots: BlobRootsList, } +impl From> for BlindedBlobsBundle { + fn from(blobs_bundle: BlobsBundle) -> Self { + BlindedBlobsBundle { + commitments: blobs_bundle.commitments, + proofs: blobs_bundle.proofs, + blob_roots: blobs_bundle + .blobs + .into_iter() + .map(|blob| blob.tree_hash_root()) + .collect::>() + .into(), + } + } +} + #[superstruct( variants(Merge, Capella, Deneb), variant_attributes( diff --git a/consensus/types/src/payload.rs b/consensus/types/src/payload.rs index 8016aaad7..a1b513d3f 100644 --- a/consensus/types/src/payload.rs +++ b/consensus/types/src/payload.rs @@ -972,9 +972,10 @@ impl From> for ExecutionPayloadHeader { } } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Encode)] #[serde(untagged)] #[serde(bound = "E: EthSpec")] +#[ssz(enum_behaviour = "transparent")] pub enum FullPayloadContents { Payload(ExecutionPayload), PayloadAndBlobs(ExecutionPayloadAndBlobs), @@ -1037,14 +1038,14 @@ impl ForkVersionDeserialize for FullPayloadContents { } } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Encode)] #[serde(bound = "E: EthSpec")] pub struct ExecutionPayloadAndBlobs { pub execution_payload: ExecutionPayload, pub blobs_bundle: BlobsBundle, } -#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, Encode)] #[serde(bound = "E: EthSpec")] pub struct BlobsBundle { pub commitments: KzgCommitments, diff --git a/consensus/types/src/signed_blob.rs b/consensus/types/src/signed_blob.rs index 7d1c553d9..ff3daa29a 100644 --- a/consensus/types/src/signed_blob.rs +++ b/consensus/types/src/signed_blob.rs @@ -59,13 +59,6 @@ impl SignedSidecar { } } -/// List of Signed Sidecars that implements `Sidecar`. -pub type SignedSidecarList = - VariableList, ::MaxBlobsPerBlock>; -pub type SignedBlobSidecarList = SignedSidecarList>; - -pub type SignedBlobSidecar = SignedSidecar>; - impl SignedBlobSidecar { /// Verify `self.signature`. /// @@ -99,3 +92,21 @@ impl SignedBlobSidecar { self.signature.verify(pubkey, message) } } + +impl From> for SignedBlindedBlobSidecar { + fn from(signed: SignedBlobSidecar) -> Self { + SignedBlindedBlobSidecar { + message: Arc::new(signed.message.into()), + signature: signed.signature, + _phantom: PhantomData, + } + } +} + +pub type SignedBlobSidecar = SignedSidecar>; +pub type SignedBlindedBlobSidecar = SignedSidecar; + +/// List of Signed Sidecars that implements `Sidecar`. +pub type SignedSidecarList = + VariableList, ::MaxBlobsPerBlock>; +pub type SignedBlobSidecarList = SignedSidecarList>; diff --git a/scripts/local_testnet/genesis.json b/scripts/local_testnet/genesis.json index 6aa439b3f..eda3b312f 100644 --- a/scripts/local_testnet/genesis.json +++ b/scripts/local_testnet/genesis.json @@ -13,7 +13,7 @@ "londonBlock": 0, "mergeNetsplitBlock": 0, "shanghaiTime": 0, - "shardingForkTime": 0, + "cancunTime": 0, "terminalTotalDifficulty": 0, "terminalTotalDifficultyPassed": true }, diff --git a/scripts/local_testnet/start_local_testnet.sh b/scripts/local_testnet/start_local_testnet.sh index 3c2b074bf..0c8cb3751 100755 --- a/scripts/local_testnet/start_local_testnet.sh +++ b/scripts/local_testnet/start_local_testnet.sh @@ -110,7 +110,7 @@ echo $CAPELLA_TIME sed -i 's/"shanghaiTime".*$/"shanghaiTime": '"$CAPELLA_TIME"',/g' $genesis_file CANCUN_TIME=$((GENESIS_TIME + (DENEB_FORK_EPOCH * 32 * SECONDS_PER_SLOT))) 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 # Delay to let boot_enr.yaml to be created @@ -141,7 +141,7 @@ sleeping 20 # Reset the `genesis.json` config file fork times. 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 secret=$DATADIR/geth_datadir$bn/geth/jwtsecret