diff --git a/Cargo.lock b/Cargo.lock index 4bea9618af..3176036456 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -178,54 +178,35 @@ checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "alloy-consensus" -version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy.git?rev=974d488bab5e21e9f17452a39a4bfa56677367b2#974d488bab5e21e9f17452a39a4bfa56677367b2" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f58047cc851e58c26224521d1ecda466e3d746ebca0274cd5427aa660a88c353" dependencies = [ "alloy-eips", - "alloy-network", "alloy-primitives", "alloy-rlp", + "c-kzg", ] [[package]] name = "alloy-eips" -version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy.git?rev=974d488bab5e21e9f17452a39a4bfa56677367b2#974d488bab5e21e9f17452a39a4bfa56677367b2" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d32a3e14fa0d152d00bd8daf605eb74ad397efb0f54bd7155585823dddb4401e" dependencies = [ "alloy-primitives", "alloy-rlp", + "c-kzg", + "once_cell", "serde", - "thiserror", -] - -[[package]] -name = "alloy-json-rpc" -version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy.git?rev=974d488bab5e21e9f17452a39a4bfa56677367b2#974d488bab5e21e9f17452a39a4bfa56677367b2" -dependencies = [ - "alloy-primitives", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "alloy-network" -version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy.git?rev=974d488bab5e21e9f17452a39a4bfa56677367b2#974d488bab5e21e9f17452a39a4bfa56677367b2" -dependencies = [ - "alloy-eips", - "alloy-json-rpc", - "alloy-primitives", - "alloy-rlp", - "serde", + "sha2 0.10.8", ] [[package]] name = "alloy-primitives" -version = "0.6.4" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "600d34d8de81e23b6d909c094e23b3d357e01ca36b78a8c5424c501eedbe86f0" +checksum = "ccb3ead547f4532bc8af961649942f0b9c16ee9226e26caa3f38420651cc0bf4" dependencies = [ "alloy-rlp", "bytes", @@ -1167,6 +1148,7 @@ dependencies = [ "glob", "hex", "libc", + "serde", ] [[package]] @@ -2864,6 +2846,7 @@ name = "execution_layer" version = "0.1.0" dependencies = [ "alloy-consensus", + "alloy-primitives", "alloy-rlp", "arc-swap", "builder_client", @@ -3552,9 +3535,6 @@ name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -dependencies = [ - "serde", -] [[package]] name = "hex-literal" @@ -6943,9 +6923,9 @@ dependencies = [ [[package]] name = "ruint" -version = "1.12.1" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f308135fef9fc398342da5472ce7c484529df23743fb7c734e0f3d472971e62" +checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286" dependencies = [ "alloy-rlp", "ark-ff 0.3.0", @@ -6967,9 +6947,9 @@ dependencies = [ [[package]] name = "ruint-macro" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f86854cf50259291520509879a5c294c3c9a4c334e9ff65071c51e42ef1e2343" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" [[package]] name = "rusqlite" @@ -8782,6 +8762,8 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" name = "types" version = "0.2.1" dependencies = [ + "alloy-primitives", + "alloy-rlp", "arbitrary", "beacon_chain", "bls", diff --git a/Cargo.toml b/Cargo.toml index d13f4f7a76..b2957842d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -94,6 +94,9 @@ resolver = "2" edition = "2021" [workspace.dependencies] +alloy-primitives = "0.7.7" +alloy-rlp = "0.3.4" +alloy-consensus = "0.2.0" anyhow = "1" arbitrary = { version = "1", features = ["derive"] } async-channel = "1.9.0" diff --git a/beacon_node/execution_layer/Cargo.toml b/beacon_node/execution_layer/Cargo.toml index ff147ad3b4..f9f599c769 100644 --- a/beacon_node/execution_layer/Cargo.toml +++ b/beacon_node/execution_layer/Cargo.toml @@ -6,6 +6,7 @@ edition = { workspace = true } # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +alloy-primitives = { workspace = true } types = { workspace = true } tokio = { workspace = true } slog = { workspace = true } @@ -48,6 +49,6 @@ hash-db = "0.15.2" pretty_reqwest_error = { workspace = true } arc-swap = "1.6.0" eth2_network_config = { workspace = true } -alloy-rlp = "0.3" -alloy-consensus = { git = "https://github.com/alloy-rs/alloy.git", rev = "974d488bab5e21e9f17452a39a4bfa56677367b2" } +alloy-rlp = { workspace = true } +alloy-consensus = { workspace = true } lighthouse_version = { workspace = true } diff --git a/beacon_node/execution_layer/src/block_hash.rs b/beacon_node/execution_layer/src/block_hash.rs index 0d0cfaf352..10edb7b2fd 100644 --- a/beacon_node/execution_layer/src/block_hash.rs +++ b/beacon_node/execution_layer/src/block_hash.rs @@ -1,13 +1,13 @@ use crate::{ - json_structures::JsonWithdrawal, + json_structures::{EncodableJsonWithdrawal, JsonWithdrawal}, keccak::{keccak256, KeccakHasher}, }; -use ethers_core::utils::rlp::RlpStream; +use alloy_rlp::Encodable; use keccak_hash::KECCAK_EMPTY_LIST_RLP; use triehash::ordered_trie_root; use types::{ - map_execution_block_header_fields_base, Address, EthSpec, ExecutionBlockHash, - ExecutionBlockHeader, ExecutionPayloadRef, Hash256, Hash64, Uint256, + EncodableExecutionBlockHeader, EthSpec, ExecutionBlockHash, ExecutionBlockHeader, + ExecutionPayloadRef, Hash256, }; /// Calculate the block hash of an execution block. @@ -60,36 +60,16 @@ pub fn calculate_execution_block_hash( /// RLP encode a withdrawal. pub fn rlp_encode_withdrawal(withdrawal: &JsonWithdrawal) -> Vec { - let mut rlp_stream = RlpStream::new(); - rlp_stream.begin_list(4); - rlp_stream.append(&withdrawal.index); - rlp_stream.append(&withdrawal.validator_index); - rlp_stream.append(&withdrawal.address); - rlp_stream.append(&withdrawal.amount); - rlp_stream.out().into() + let mut out: Vec = vec![]; + EncodableJsonWithdrawal::from(withdrawal).encode(&mut out); + out } /// RLP encode an execution block header. pub fn rlp_encode_block_header(header: &ExecutionBlockHeader) -> Vec { - let mut rlp_header_stream = RlpStream::new(); - rlp_header_stream.begin_unbounded_list(); - map_execution_block_header_fields_base!(&header, |_, field| { - rlp_header_stream.append(field); - }); - if let Some(withdrawals_root) = &header.withdrawals_root { - rlp_header_stream.append(withdrawals_root); - } - if let Some(blob_gas_used) = &header.blob_gas_used { - rlp_header_stream.append(blob_gas_used); - } - if let Some(excess_blob_gas) = &header.excess_blob_gas { - rlp_header_stream.append(excess_blob_gas); - } - if let Some(parent_beacon_block_root) = &header.parent_beacon_block_root { - rlp_header_stream.append(parent_beacon_block_root); - } - rlp_header_stream.finalize_unbounded_list(); - rlp_header_stream.out().into() + let mut out: Vec = vec![]; + EncodableExecutionBlockHeader::from(header).encode(&mut out); + out } #[cfg(test)] @@ -97,6 +77,7 @@ mod test { use super::*; use hex::FromHex; use std::str::FromStr; + use types::{Address, Hash256, Hash64}; fn test_rlp_encoding( header: &ExecutionBlockHeader, diff --git a/beacon_node/execution_layer/src/engine_api/json_structures.rs b/beacon_node/execution_layer/src/engine_api/json_structures.rs index fbffc47e29..f654ba4a0e 100644 --- a/beacon_node/execution_layer/src/engine_api/json_structures.rs +++ b/beacon_node/execution_layer/src/engine_api/json_structures.rs @@ -1,4 +1,5 @@ use super::*; +use alloy_rlp::RlpEncodable; use serde::{Deserialize, Serialize}; use strum::EnumString; use superstruct::superstruct; @@ -463,6 +464,24 @@ impl From for Withdrawal { } } } +#[derive(Debug, PartialEq, Clone, RlpEncodable)] +pub struct EncodableJsonWithdrawal<'a> { + pub index: u64, + pub validator_index: u64, + pub address: &'a [u8], + pub amount: u64, +} + +impl<'a> From<&'a JsonWithdrawal> for EncodableJsonWithdrawal<'a> { + fn from(json_withdrawal: &'a JsonWithdrawal) -> Self { + Self { + index: json_withdrawal.index, + validator_index: json_withdrawal.validator_index, + address: json_withdrawal.address.as_bytes(), + amount: json_withdrawal.amount, + } + } +} #[superstruct( variants(V1, V2, V3), diff --git a/beacon_node/execution_layer/src/keccak.rs b/beacon_node/execution_layer/src/keccak.rs index c4c9689272..62e354d503 100644 --- a/beacon_node/execution_layer/src/keccak.rs +++ b/beacon_node/execution_layer/src/keccak.rs @@ -16,7 +16,7 @@ use hash_db::Hasher; use types::Hash256; pub fn keccak256(bytes: &[u8]) -> Hash256 { - Hash256::from(ethers_core::utils::keccak256(bytes)) + Hash256::from(alloy_primitives::utils::keccak256(bytes).as_ref()) } /// Keccak hasher. diff --git a/beacon_node/execution_layer/src/versioned_hashes.rs b/beacon_node/execution_layer/src/versioned_hashes.rs index 9bf87596b4..97c3100de9 100644 --- a/beacon_node/execution_layer/src/versioned_hashes.rs +++ b/beacon_node/execution_layer/src/versioned_hashes.rs @@ -42,22 +42,17 @@ pub fn extract_versioned_hashes_from_transactions( let mut versioned_hashes = Vec::new(); for tx in transactions { - match beacon_tx_to_tx_envelope(tx)? { - TxEnvelope::Eip4844(signed_tx_eip4844) => { - versioned_hashes.extend( - signed_tx_eip4844 - .tx() - .blob_versioned_hashes - .iter() - .map(|fb| Hash256::from(fb.0)), - ); - } - // enumerating all variants explicitly to make pattern irrefutable - // in case new types are added in the future which also have blobs - TxEnvelope::Legacy(_) - | TxEnvelope::TaggedLegacy(_) - | TxEnvelope::Eip2930(_) - | TxEnvelope::Eip1559(_) => {} + // TxEnvelope is non-exhaustive so unforunately we can (no longer) write an exhaustive + // match here. + if let TxEnvelope::Eip4844(signed_tx_eip4844) = beacon_tx_to_tx_envelope(tx)? { + versioned_hashes.extend( + signed_tx_eip4844 + .tx() + .tx() + .blob_versioned_hashes + .iter() + .map(|fb| Hash256::from(fb.0)), + ); } } @@ -76,7 +71,8 @@ pub fn beacon_tx_to_tx_envelope( mod test { use super::*; use crate::test_utils::static_valid_tx; - use alloy_consensus::{TxKind, TxLegacy}; + use alloy_consensus::TxLegacy; + use alloy_primitives::TxKind; type E = types::MainnetEthSpec; diff --git a/consensus/types/Cargo.toml b/consensus/types/Cargo.toml index 28207f828a..f623f3d101 100644 --- a/consensus/types/Cargo.toml +++ b/consensus/types/Cargo.toml @@ -9,6 +9,7 @@ name = "benches" harness = false [dependencies] +alloy-primitives = { workspace = true, features = ["rlp"] } merkle_proof = { workspace = true } bls = { workspace = true, features = ["arbitrary"] } kzg = { workspace = true } @@ -50,6 +51,7 @@ metastruct = "0.1.0" serde_json = { workspace = true } smallvec = { workspace = true } maplit = { workspace = true } +alloy-rlp = { version = "0.3.4", features = ["derive"] } milhouse = { workspace = true } rpds = { workspace = true } diff --git a/consensus/types/src/execution_block_header.rs b/consensus/types/src/execution_block_header.rs index 945222a925..2e5a498214 100644 --- a/consensus/types/src/execution_block_header.rs +++ b/consensus/types/src/execution_block_header.rs @@ -18,6 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. use crate::{Address, EthSpec, ExecutionPayloadRef, Hash256, Hash64, Uint256}; +use alloy_rlp::RlpEncodable; use metastruct::metastruct; /// Execution block header as used for RLP encoding and Keccak hashing. @@ -89,3 +90,74 @@ impl ExecutionBlockHeader { } } } + +#[derive(Debug, Clone, PartialEq, Eq, RlpEncodable)] +#[rlp(trailing)] +pub struct EncodableExecutionBlockHeader<'a> { + pub parent_hash: &'a [u8], + pub ommers_hash: &'a [u8], + pub beneficiary: &'a [u8], + pub state_root: &'a [u8], + pub transactions_root: &'a [u8], + pub receipts_root: &'a [u8], + pub logs_bloom: &'a [u8], + pub difficulty: alloy_primitives::U256, + pub number: alloy_primitives::U256, + pub gas_limit: alloy_primitives::U256, + pub gas_used: alloy_primitives::U256, + pub timestamp: u64, + pub extra_data: &'a [u8], + pub mix_hash: &'a [u8], + pub nonce: &'a [u8], + pub base_fee_per_gas: alloy_primitives::U256, + pub withdrawals_root: Option<&'a [u8]>, + pub blob_gas_used: Option, + pub excess_blob_gas: Option, + pub parent_beacon_block_root: Option<&'a [u8]>, +} + +impl<'a> From<&'a ExecutionBlockHeader> for EncodableExecutionBlockHeader<'a> { + fn from(header: &'a ExecutionBlockHeader) -> Self { + let mut encodable = Self { + parent_hash: header.parent_hash.as_bytes(), + ommers_hash: header.ommers_hash.as_bytes(), + beneficiary: header.beneficiary.as_bytes(), + state_root: header.state_root.as_bytes(), + transactions_root: header.transactions_root.as_bytes(), + receipts_root: header.receipts_root.as_bytes(), + logs_bloom: header.logs_bloom.as_slice(), + difficulty: U256Shim(header.difficulty).into(), + number: U256Shim(header.number).into(), + gas_limit: U256Shim(header.gas_limit).into(), + gas_used: U256Shim(header.gas_used).into(), + timestamp: header.timestamp, + extra_data: header.extra_data.as_slice(), + mix_hash: header.mix_hash.as_bytes(), + nonce: header.nonce.as_bytes(), + base_fee_per_gas: U256Shim(header.base_fee_per_gas).into(), + withdrawals_root: None, + blob_gas_used: header.blob_gas_used, + excess_blob_gas: header.excess_blob_gas, + parent_beacon_block_root: None, + }; + if let Some(withdrawals_root) = &header.withdrawals_root { + encodable.withdrawals_root = Some(withdrawals_root.as_bytes()); + } + if let Some(parent_beacon_block_root) = &header.parent_beacon_block_root { + encodable.parent_beacon_block_root = Some(parent_beacon_block_root.as_bytes()) + } + encodable + } +} + +// TODO(alloy) this shim can be removed once we fully migrate +// from ethereum types to alloy primitives +struct U256Shim(Uint256); + +impl From for alloy_primitives::U256 { + fn from(value: U256Shim) -> Self { + let mut buffer: [u8; 32] = [0; 32]; + value.0.to_little_endian(&mut buffer); + Self::from_le_slice(&buffer) + } +} diff --git a/consensus/types/src/lib.rs b/consensus/types/src/lib.rs index b5c500f0b2..89c14fa0ad 100644 --- a/consensus/types/src/lib.rs +++ b/consensus/types/src/lib.rs @@ -157,7 +157,7 @@ pub use crate::epoch_cache::{EpochCache, EpochCacheError, EpochCacheKey}; pub use crate::eth1_data::Eth1Data; pub use crate::eth_spec::EthSpecId; pub use crate::execution_block_hash::ExecutionBlockHash; -pub use crate::execution_block_header::ExecutionBlockHeader; +pub use crate::execution_block_header::{EncodableExecutionBlockHeader, ExecutionBlockHeader}; pub use crate::execution_layer_withdrawal_request::ExecutionLayerWithdrawalRequest; pub use crate::execution_payload::{ ExecutionPayload, ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadDeneb,