diff --git a/Cargo.toml b/Cargo.toml index 58891d39..3e819b08 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,12 +27,14 @@ cb-pbs = { path = "crates/pbs" } cb-signer = { path = "crates/signer" } # ethereum -alloy = { version = "0.2.0", features = ["rpc-types-beacon"] } -ethereum_ssz = "0.5" -ethereum_ssz_derive = "0.5.3" -ssz_types = "0.5" -ethereum_serde_utils = "0.5.2" -ethereum-types = "0.14.1" +alloy = { version = "0.3.6", features = [ + "rpc-types-beacon", + "serde", + "ssz", + "getrandom", +] } +ssz_types = "0.8" +ethereum_serde_utils = "0.7.0" # networking axum = { version = "0.7.5", features = ["macros"] } @@ -60,8 +62,8 @@ prometheus = "0.13.4" # crypto blst = "0.3.11" -tree_hash = "0.5" -tree_hash_derive = "0.5" +tree_hash = "0.8" +tree_hash_derive = "0.8" eth2_keystore = { git = "https://github.com/sigp/lighthouse", rev = "9e12c21f268c80a3f002ae0ca27477f9f512eb6f" } k256 = "0.13" diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml index dd5fa824..24ab4a54 100644 --- a/crates/common/Cargo.toml +++ b/crates/common/Cargo.toml @@ -7,12 +7,9 @@ publish = false [dependencies] # ethereum -alloy = { workspace = true, features = ["ssz"] } -ethereum_ssz.workspace = true +alloy = { workspace = true } ssz_types.workspace = true -ethereum_ssz_derive.workspace = true ethereum_serde_utils.workspace = true -ethereum-types.workspace = true # networking axum.workspace = true diff --git a/crates/common/src/commit/request.rs b/crates/common/src/commit/request.rs index c1d7ed77..1b0fd491 100644 --- a/crates/common/src/commit/request.rs +++ b/crates/common/src/commit/request.rs @@ -3,8 +3,6 @@ use std::fmt::{self, Debug, Display, LowerHex}; use alloy::rpc::types::beacon::BlsSignature; use derive_more::derive::From; use serde::{Deserialize, Serialize}; -use ssz::{Decode, Encode}; -use ssz_derive::{Decode, Encode}; use tree_hash::TreeHash; use tree_hash_derive::TreeHash; @@ -16,17 +14,14 @@ use crate::{ types::Chain, }; -pub trait PublicKey: - AsRef<[u8]> + Debug + Clone + Copy + Encode + Decode + TreeHash + Display + LowerHex -{ -} +pub trait PublicKey: AsRef<[u8]> + Debug + Clone + Copy + TreeHash + Display + LowerHex {} impl PublicKey for EcdsaPublicKey {} impl PublicKey for BlsPublicKey {} // GENERIC PROXY DELEGATION -#[derive(Debug, Clone, Copy, Serialize, Deserialize, Encode, Decode, TreeHash)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize, TreeHash)] pub struct ProxyDelegation { pub delegator: BlsPublicKey, pub proxy: T, diff --git a/crates/common/src/pbs/types/beacon_block.rs b/crates/common/src/pbs/types/beacon_block.rs index 8f352107..e17f1f8a 100644 --- a/crates/common/src/pbs/types/beacon_block.rs +++ b/crates/common/src/pbs/types/beacon_block.rs @@ -1,13 +1,12 @@ use alloy::{primitives::B256, rpc::types::beacon::BlsSignature}; use serde::{Deserialize, Serialize}; -use ssz_derive::{Decode, Encode}; use super::{ blinded_block_body::BlindedBeaconBlockBody, blobs_bundle::BlobsBundle, execution_payload::ExecutionPayload, spec::DenebSpec, utils::VersionedResponse, }; -#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] /// Sent to relays in submit_block pub struct SignedBlindedBeaconBlock { pub message: BlindedBeaconBlock, @@ -20,7 +19,7 @@ impl SignedBlindedBeaconBlock { } } -#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct BlindedBeaconBlock { #[serde(with = "serde_utils::quoted_u64")] pub slot: u64, @@ -34,7 +33,7 @@ pub struct BlindedBeaconBlock { /// Returned by relay in submit_block pub type SubmitBlindedBlockResponse = VersionedResponse; -#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct PayloadAndBlobs { pub execution_payload: ExecutionPayload, pub blobs_bundle: Option>, @@ -48,7 +47,10 @@ impl SubmitBlindedBlockResponse { #[cfg(test)] mod tests { + use serde_json::json; + use super::{SignedBlindedBeaconBlock, SubmitBlindedBlockResponse}; + use crate::utils::test_encode_decode; #[test] // this is from the builder api spec, but with sync_committee_bits fixed to @@ -248,7 +250,7 @@ mod tests { "signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505" }"#; - assert!(serde_json::from_str::(&data).is_ok()); + test_encode_decode::(&data); } #[test] @@ -535,7 +537,7 @@ mod tests { }, "execution_payload_header": { "parent_hash": "0xa330251430b91a6fb5342f30a1f527dc76499c03a411464235951dbd51b94d9f", - "fee_recipient": "0xf97e180c050e5Ab072211Ad2C213Eb5AEE4DF134", + "fee_recipient": "0xf97e180c050e5ab072211ad2c213eb5aee4df134", "state_root": "0x079f2cc22a29388fd4fc20f451cbaa3ff39845d68b2c368ff7be314617418e38", "receipts_root": "0xed980a4cf6df8ba330c14ed9fe0597ec20515f44e5a9adfd2f7b72aa14890996", "logs_bloom": "0x0000000400000008000008000040000000000000000000001000104880000200000004000000400000000204000020002000000000000000000000000022000800000004000000000002000c000000000000000000000100000000000000000000000000000000000000000000000040000000000040000001000014000000010002104000000000000000000000000000000000000000000000000000000080020000000000000000002400000000000001000000000002000200102000000040100002000000000000000000000000000000000000000800000000000000000010000000000000000000000000000000000400002000000000000000200000", @@ -562,19 +564,19 @@ mod tests { "signature": "0x8c3095fd9d3a18e43ceeb7648281e16bb03044839dffea796432c4e5a1372bef22c11a98a31e0c1c5389b98cc6d45917170a0f1634bcf152d896f360dc599fabba2ec4de77898b5dff080fa1628482bdbad5b37d2e64fea3d8721095186cfe50" }"#; - assert!(serde_json::from_str::(&data).is_ok()); + test_encode_decode::(&data); } #[test] // this is from the builder api spec, but with blobs fixed to deserialize // correctly fn test_submit_blinded_block_response() { - let blob = alloy::primitives::hex::encode([1; 131072]); - let data = format!( - r#"{{ + let blob = alloy::primitives::hex::encode_prefixed([1; 131072]); + + let data = json!({ "version": "deneb", - "data": {{ - "execution_payload": {{ + "data": { + "execution_payload": { "parent_hash": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", "fee_recipient": "0xabcf8e0d4e9587369b2301d0790347320302cc09", @@ -598,15 +600,15 @@ mod tests { "0x02f878831469668303f51d843b9ac9f9843b9aca0082520894c93269b73096998db66be0441e836d873535cb9c8894a19041886f000080c001a031cc29234036afbf9a1fb9476b463367cb1f957ac0b919b69bbc798436e604aaa018c4e9c3914eb27aadd0b91e10b18655739fcf8c1fc398763a9f1beecb8ddc86" ], "withdrawals": [ - {{ + { "index": "1", "validator_index": "1", "address": "0xabcf8e0d4e9587369b2301d0790347320302cc09", "amount": "32000000000" - }} + } ] - }}, - "blobs_bundle": {{ + }, + "blobs_bundle": { "commitments": [ "0x8dab030c51e16e84be9caab84ee3d0b8bbec1db4a0e4de76439da8424d9b957370a10a78851f97e4b54d2ce1ab0d686f" ], @@ -614,14 +616,12 @@ mod tests { "0xb4021b0de10f743893d4f71e1bf830c019e832958efd6795baf2f83b8699a9eccc5dc99015d8d4d8ec370d0cc333c06a" ], "blobs": [ - "0x{}" + blob ] - }} - }} - }}"#, - blob - ); + } + } + }).to_string(); - assert!(serde_json::from_str::(&data).is_ok()); + test_encode_decode::(&data); } } diff --git a/crates/common/src/pbs/types/blinded_block_body.rs b/crates/common/src/pbs/types/blinded_block_body.rs index ebad3671..ded4f215 100644 --- a/crates/common/src/pbs/types/blinded_block_body.rs +++ b/crates/common/src/pbs/types/blinded_block_body.rs @@ -3,7 +3,6 @@ use alloy::{ rpc::types::beacon::{BlsPublicKey, BlsSignature}, }; use serde::{Deserialize, Serialize}; -use ssz_derive::{Decode, Encode}; use ssz_types::{typenum, BitList, BitVector, FixedVector, VariableList}; use super::{ @@ -11,7 +10,7 @@ use super::{ }; use crate::utils::as_str; -#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct BlindedBeaconBlockBody { pub randao_reveal: BlsSignature, pub eth1_data: Eth1Data, @@ -28,7 +27,7 @@ pub struct BlindedBeaconBlockBody { pub blob_kzg_commitments: KzgCommitments, } -#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct Eth1Data { pub deposit_root: B256, #[serde(with = "serde_utils::quoted_u64")] @@ -36,7 +35,7 @@ pub struct Eth1Data { pub block_hash: B256, } -#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct BeaconBlockHeader { #[serde(with = "serde_utils::quoted_u64")] pub slot: u64, @@ -47,13 +46,13 @@ pub struct BeaconBlockHeader { pub body_root: B256, } -#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct SignedBeaconBlockHeader { pub message: BeaconBlockHeader, pub signature: BlsSignature, } -#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct BlsToExecutionChange { #[serde(with = "as_str")] pub validator_index: u64, @@ -61,25 +60,25 @@ pub struct BlsToExecutionChange { pub to_execution_address: Address, } -#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct SignedBlsToExecutionChange { pub message: BlsToExecutionChange, pub signature: BlsSignature, } -#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct ProposerSlashing { pub signed_header_1: SignedBeaconBlockHeader, pub signed_header_2: SignedBeaconBlockHeader, } -#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct AttesterSlashing { pub attestation_1: IndexedAttestation, pub attestation_2: IndexedAttestation, } -#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] #[serde(bound = "T: EthSpec")] pub struct IndexedAttestation { /// Lists validator registry indices, not committee indices. @@ -89,7 +88,7 @@ pub struct IndexedAttestation { pub signature: BlsSignature, } -#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct AttestationData { #[serde(with = "serde_utils::quoted_u64")] pub slot: u64, @@ -102,14 +101,14 @@ pub struct AttestationData { pub target: Checkpoint, } -#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct Checkpoint { #[serde(with = "serde_utils::quoted_u64")] pub epoch: u64, pub root: B256, } -#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Clone, Serialize, Deserialize)] #[serde(bound = "T: EthSpec")] pub struct Attestation { pub aggregation_bits: BitList, @@ -117,13 +116,13 @@ pub struct Attestation { pub signature: BlsSignature, } -#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct Deposit { pub proof: FixedVector, // put this in EthSpec? pub data: DepositData, } -#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct DepositData { pub pubkey: BlsPublicKey, pub withdrawal_credentials: B256, @@ -132,13 +131,13 @@ pub struct DepositData { pub signature: BlsSignature, } -#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct SignedVoluntaryExit { pub message: VoluntaryExit, pub signature: BlsSignature, } -#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct VoluntaryExit { /// Earliest epoch when voluntary exit can be processed. #[serde(with = "serde_utils::quoted_u64")] @@ -147,7 +146,7 @@ pub struct VoluntaryExit { pub validator_index: u64, } -#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] #[serde(bound = "T: EthSpec")] pub struct SyncAggregate { pub sync_committee_bits: BitVector, diff --git a/crates/common/src/pbs/types/blobs_bundle.rs b/crates/common/src/pbs/types/blobs_bundle.rs index c861a930..778679b2 100644 --- a/crates/common/src/pbs/types/blobs_bundle.rs +++ b/crates/common/src/pbs/types/blobs_bundle.rs @@ -1,5 +1,4 @@ use serde::{Deserialize, Serialize}; -use ssz_derive::{Decode, Encode}; use ssz_types::{FixedVector, VariableList}; use super::{ @@ -7,7 +6,7 @@ use super::{ spec::EthSpec, }; -#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] #[serde(bound = "T: EthSpec")] pub struct BlobsBundle { pub commitments: KzgCommitments, diff --git a/crates/common/src/pbs/types/execution_payload.rs b/crates/common/src/pbs/types/execution_payload.rs index 8c75ef9c..e593f5f1 100644 --- a/crates/common/src/pbs/types/execution_payload.rs +++ b/crates/common/src/pbs/types/execution_payload.rs @@ -1,19 +1,15 @@ -use alloy::primitives::{Address, B256, U256}; -use ethereum_types::{Address as EAddress, U256 as EU256}; +use alloy::primitives::{b256, Address, B256, U256}; use serde::{Deserialize, Serialize}; -use ssz_derive::{Decode, Encode}; use ssz_types::{FixedVector, VariableList}; use tree_hash_derive::TreeHash; -use super::{spec::EthSpec, utils::*}; +use super::spec::EthSpec; use crate::utils::as_str; -pub const EMPTY_TX_ROOT_HASH: [u8; 32] = [ - 127, 254, 36, 30, 166, 1, 135, 253, 176, 24, 123, 250, 34, 222, 53, 209, 249, 190, 215, 171, 6, - 29, 148, 1, 253, 71, 227, 74, 84, 251, 237, 225, -]; +pub const EMPTY_TX_ROOT_HASH: B256 = + b256!("7ffe241ea60187fdb0187bfa22de35d1f9bed7ab061d9401fd47e34a54fbede1"); -#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct ExecutionPayload { pub parent_hash: B256, pub fee_recipient: Address, @@ -50,7 +46,7 @@ pub type Transactions = VariableList< >; pub type Transaction = VariableList; -#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct Withdrawal { #[serde(with = "serde_utils::quoted_u64")] pub index: u64, @@ -61,10 +57,10 @@ pub struct Withdrawal { pub amount: u64, } -#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode, TreeHash)] +#[derive(Debug, Default, Clone, Serialize, Deserialize, TreeHash)] pub struct ExecutionPayloadHeader { pub parent_hash: B256, - pub fee_recipient: EAddress, + pub fee_recipient: Address, pub state_root: B256, pub receipts_root: B256, #[serde(with = "ssz_types::serde_utils::hex_fixed_vec")] @@ -80,8 +76,8 @@ pub struct ExecutionPayloadHeader { pub timestamp: u64, #[serde(with = "ssz_types::serde_utils::hex_var_list")] pub extra_data: VariableList, - #[serde(with = "as_dec_str")] - base_fee_per_gas: EU256, + #[serde(with = "serde_utils::quoted_u256")] + pub base_fee_per_gas: U256, pub block_hash: B256, pub transactions_root: B256, pub withdrawals_root: B256, @@ -93,20 +89,52 @@ pub struct ExecutionPayloadHeader { #[cfg(test)] mod tests { + use alloy::primitives::b256; use ssz_types::VariableList; use tree_hash::TreeHash; - use crate::pbs::types::{execution_payload::Transactions, spec::DenebSpec, EMPTY_TX_ROOT_HASH}; + use super::*; + use crate::{ + pbs::types::{execution_payload::Transactions, spec::DenebSpec}, + utils::test_encode_decode, + }; #[test] fn test_empty_tx_root_hash() { let txs: Transactions = VariableList::empty(); let txs_root = txs.tree_hash_root(); - assert_eq!(txs_root.0, EMPTY_TX_ROOT_HASH); + assert_eq!(txs_root, EMPTY_TX_ROOT_HASH); + } + + #[test] + fn test_execution_payload_header() { + let data = r#"{ + "parent_hash": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "fee_recipient": "0xabcf8e0d4e9587369b2301d0790347320302cc09", + "state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "receipts_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "prev_randao": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "block_number": "1", + "gas_limit": "1", + "gas_used": "1", + "timestamp": "1", + "extra_data": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "base_fee_per_gas": "150", + "block_hash": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "transactions_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "withdrawals_root": "0x2daccf0e476ca3e2644afbd13b2621d55b4d515b813a3b867cdacea24bb352d1", + "blob_gas_used": "786432", + "excess_blob_gas": "95158272" + }"#; + + let parsed = test_encode_decode::>(&data); + assert_eq!( - format!("{txs_root:?}"), - "0x7ffe241ea60187fdb0187bfa22de35d1f9bed7ab061d9401fd47e34a54fbede1" + parsed.parent_hash, + b256!("cf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2") ); + assert_eq!(parsed.base_fee_per_gas, U256::from(150)); } } diff --git a/crates/common/src/pbs/types/get_header.rs b/crates/common/src/pbs/types/get_header.rs index c040f9ea..f8591a24 100644 --- a/crates/common/src/pbs/types/get_header.rs +++ b/crates/common/src/pbs/types/get_header.rs @@ -2,16 +2,12 @@ use alloy::{ primitives::{B256, U256}, rpc::types::beacon::{BlsPublicKey, BlsSignature}, }; -use ethereum_types::U256 as EU256; use serde::{Deserialize, Serialize}; -use ssz_derive::{Decode, Encode}; use tree_hash_derive::TreeHash; use super::{ - execution_payload::ExecutionPayloadHeader, - kzg::KzgCommitments, - spec::DenebSpec, - utils::{as_dec_str, VersionedResponse}, + execution_payload::ExecutionPayloadHeader, kzg::KzgCommitments, spec::DenebSpec, + utils::VersionedResponse, }; #[derive(Debug, Serialize, Deserialize, Clone, Copy)] @@ -34,36 +30,25 @@ impl GetHeaderResponse { } pub fn value(&self) -> U256 { - self.data.message.value() + self.data.message.value } } -#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct SignedExecutionPayloadHeader { pub message: ExecutionPayloadHeaderMessage, pub signature: BlsSignature, } -#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode, TreeHash)] +#[derive(Debug, Default, Clone, Serialize, Deserialize, TreeHash)] pub struct ExecutionPayloadHeaderMessage { pub header: ExecutionPayloadHeader, pub blob_kzg_commitments: KzgCommitments, - #[serde(with = "as_dec_str")] - value: EU256, + #[serde(with = "serde_utils::quoted_u256")] + pub value: U256, pub pubkey: BlsPublicKey, } -impl ExecutionPayloadHeaderMessage { - pub fn value(&self) -> U256 { - U256::from_limbs(self.value.0) - } - - // FIMXE: only used in test - pub fn set_value(&mut self, value: U256) { - self.value = EU256::from_little_endian(&value.to_le_bytes::<32>()) - } -} - #[cfg(test)] mod tests { use alloy::primitives::U256; @@ -71,6 +56,7 @@ mod tests { use super::GetHeaderResponse; use crate::{ constants::APPLICATION_BUILDER_DOMAIN, signature::verify_signed_message, types::Chain, + utils::test_encode_decode, }; #[test] @@ -113,9 +99,9 @@ mod tests { } }"#; - let parsed = serde_json::from_str::(&data).unwrap().data; + let parsed = test_encode_decode::(&data).data; - assert_eq!(parsed.message.value(), U256::from(4293912964927787u64)); + assert_eq!(parsed.message.value, U256::from(4293912964927787u64)); assert!(verify_signed_message( Chain::Holesky, diff --git a/crates/common/src/pbs/types/kzg.rs b/crates/common/src/pbs/types/kzg.rs index 8bbd1aa8..c1ff15a2 100644 --- a/crates/common/src/pbs/types/kzg.rs +++ b/crates/common/src/pbs/types/kzg.rs @@ -4,15 +4,13 @@ use std::{ }; use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use ssz_derive::{Decode, Encode}; use ssz_types::VariableList; use tree_hash::{PackedEncoding, TreeHash}; use super::spec::EthSpec; pub const BYTES_PER_COMMITMENT: usize = 48; -#[derive(Clone, Encode, Decode, Eq, PartialEq)] -#[ssz(struct_behaviour = "transparent")] +#[derive(Clone, Eq, PartialEq)] pub struct KzgCommitment(pub [u8; BYTES_PER_COMMITMENT]); pub type KzgCommitments = VariableList::MaxBlobCommitmentsPerBlock>; @@ -98,8 +96,7 @@ impl FromStr for KzgCommitment { // PROOF const BYTES_PER_PROOF: usize = 48; -#[derive(Debug, Clone, Encode, Decode)] -#[ssz(struct_behaviour = "transparent")] +#[derive(Debug, Clone)] pub struct KzgProof(pub [u8; BYTES_PER_PROOF]); pub type KzgProofs = VariableList::MaxBlobCommitmentsPerBlock>; diff --git a/crates/common/src/pbs/types/spec.rs b/crates/common/src/pbs/types/spec.rs index 73e7ad0b..09a1afb3 100644 --- a/crates/common/src/pbs/types/spec.rs +++ b/crates/common/src/pbs/types/spec.rs @@ -1,5 +1,4 @@ use serde::{Deserialize, Serialize}; -use ssz_derive::{Decode, Encode}; use ssz_types::typenum; pub trait EthSpec { @@ -20,7 +19,7 @@ pub trait EthSpec { type BytesPerBlob: typenum::Unsigned + std::fmt::Debug; } -#[derive(Debug, Default, Clone, Serialize, Deserialize, Encode, Decode)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct DenebSpec; impl EthSpec for DenebSpec { diff --git a/crates/common/src/pbs/types/utils.rs b/crates/common/src/pbs/types/utils.rs index 4ec53b69..2aeb1793 100644 --- a/crates/common/src/pbs/types/utils.rs +++ b/crates/common/src/pbs/types/utils.rs @@ -29,27 +29,6 @@ pub mod quoted_variable_list_u64 { } } -pub mod as_dec_str { - use ethereum_types::U256; - use serde::Deserialize; - - pub fn serialize(data: &U256, serializer: S) -> Result - where - S: serde::Serializer, - { - let s = data.to_string(); - serializer.serialize_str(&s) - } - - pub fn deserialize<'de, D>(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let s = String::deserialize(deserializer)?; - U256::from_dec_str(&s).map_err(serde::de::Error::custom) - } -} - #[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct VersionedResponse { pub version: Version, diff --git a/crates/common/src/signature.rs b/crates/common/src/signature.rs index c939cd41..de9f477b 100644 --- a/crates/common/src/signature.rs +++ b/crates/common/src/signature.rs @@ -1,5 +1,4 @@ use alloy::rpc::types::beacon::{constants::BLS_DST_SIG, BlsPublicKey, BlsSignature}; -use ssz_derive::{Decode, Encode}; use tree_hash::TreeHash; use tree_hash_derive::TreeHash; @@ -16,7 +15,7 @@ pub fn sign_message(secret_key: &BlsSecretKey, msg: &[u8]) -> BlsSignature { } pub fn compute_signing_root(object_root: [u8; 32], signing_domain: [u8; 32]) -> [u8; 32] { - #[derive(Default, Debug, Encode, Decode, TreeHash)] + #[derive(Default, Debug, TreeHash)] struct SigningData { object_root: [u8; 32], signing_domain: [u8; 32], @@ -27,7 +26,7 @@ pub fn compute_signing_root(object_root: [u8; 32], signing_domain: [u8; 32]) -> } pub fn compute_domain(chain: Chain, domain_mask: [u8; 4]) -> [u8; 32] { - #[derive(Debug, Encode, Decode, TreeHash)] + #[derive(Debug, TreeHash)] struct ForkData { fork_version: [u8; 4], genesis_validators_root: [u8; 32], diff --git a/crates/common/src/signer/schemes/bls.rs b/crates/common/src/signer/schemes/bls.rs index 39942ca7..4f901a1f 100644 --- a/crates/common/src/signer/schemes/bls.rs +++ b/crates/common/src/signer/schemes/bls.rs @@ -3,7 +3,6 @@ use alloy::rpc::types::beacon::{constants::BLS_DST_SIG, BlsPublicKey as BlsPubli use blst::BLST_ERROR; use derive_more::derive::{Deref, Display, From, Into, LowerHex}; use serde::{Deserialize, Serialize}; -use ssz_derive::{Decode, Encode}; use tree_hash::TreeHash; use tree_hash_derive::TreeHash; @@ -23,8 +22,7 @@ pub type BlsSecretKey = blst::min_pk::SecretKey; // std traits #[derive(Debug, Clone, Copy, LowerHex, Display, PartialEq, Eq, Hash, Default)] // serde, ssz, tree_hash -#[derive(Serialize, Deserialize, Encode, Decode, TreeHash)] -#[ssz(struct_behaviour = "transparent")] +#[derive(Serialize, Deserialize, TreeHash)] #[serde(transparent)] // derive_more #[derive(Deref, From, Into)] diff --git a/crates/common/src/signer/schemes/ecdsa.rs b/crates/common/src/signer/schemes/ecdsa.rs index df4f4840..e813a7a7 100644 --- a/crates/common/src/signer/schemes/ecdsa.rs +++ b/crates/common/src/signer/schemes/ecdsa.rs @@ -67,50 +67,6 @@ impl TreeHash for EcdsaPublicKey { } } -impl ssz::Encode for EcdsaPublicKey { - #[inline] - fn is_ssz_fixed_len() -> bool { - true - } - - fn ssz_bytes_len(&self) -> usize { - Self::SIZE - } - - #[inline] - fn ssz_fixed_len() -> usize { - Self::SIZE - } - - #[inline] - fn ssz_append(&self, buf: &mut Vec) { - buf.extend_from_slice(&self.encoded) - } - - #[inline] - fn as_ssz_bytes(&self) -> Vec { - self.encoded.to_vec() - } -} - -impl ssz::Decode for EcdsaPublicKey { - fn is_ssz_fixed_len() -> bool { - true - } - - fn ssz_fixed_len() -> usize { - Self::SIZE - } - - fn from_ssz_bytes(bytes: &[u8]) -> Result { - let encoded = <[u8; 33]>::try_from(bytes).map_err(|_| { - ssz::DecodeError::InvalidByteLength { len: bytes.len(), expected: Self::SIZE } - })?; - - Ok(EcdsaPublicKey { encoded }) - } -} - impl From for EcdsaPublicKey { fn from(value: EcdsaPublicKeyInner) -> Self { let encoded: [u8; Self::SIZE] = value.to_encoded_point(true).as_bytes().try_into().unwrap(); diff --git a/crates/common/src/utils.rs b/crates/common/src/utils.rs index 4673f4ff..8ea63014 100644 --- a/crates/common/src/utils.rs +++ b/crates/common/src/utils.rs @@ -8,6 +8,8 @@ use axum::http::HeaderValue; use blst::min_pk::{PublicKey, Signature}; use rand::{distributions::Alphanumeric, Rng}; use reqwest::header::HeaderMap; +use serde::{de::DeserializeOwned, Serialize}; +use serde_json::Value; use tracing::Level; use tracing_appender::{non_blocking::WorkerGuard, rolling::Rotation}; use tracing_subscriber::{fmt::Layer, prelude::*, EnvFilter}; @@ -58,6 +60,19 @@ pub fn eth_to_wei(eth: f64) -> U256 { } // Serde +/// Test that the encoding and decoding works, returns the decoded struct +pub fn test_encode_decode(d: &str) -> T { + let decoded = serde_json::from_str::(d).expect("deserialize"); + + // re-encode to make sure that different formats are ignored + let encoded = serde_json::to_string(&decoded).unwrap(); + let original_v: Value = serde_json::from_str(d).unwrap(); + let encoded_v: Value = serde_json::from_str(&encoded).unwrap(); + assert_eq!(original_v, encoded_v, "encode mismatch"); + + decoded +} + pub mod as_str { use std::{fmt::Display, str::FromStr}; diff --git a/crates/pbs/src/mev_boost/get_header.rs b/crates/pbs/src/mev_boost/get_header.rs index df3be77f..e98b3e49 100644 --- a/crates/pbs/src/mev_boost/get_header.rs +++ b/crates/pbs/src/mev_boost/get_header.rs @@ -293,7 +293,7 @@ fn validate_header( let block_hash = signed_header.message.header.block_hash; let received_relay_pubkey = signed_header.message.pubkey; let tx_root = signed_header.message.header.transactions_root; - let value = signed_header.message.value(); + let value = signed_header.message.value; if block_hash == B256::ZERO { return Err(ValidationError::EmptyBlockhash); @@ -365,8 +365,7 @@ mod tests { .unwrap(); let pubkey = BlsPublicKey::from_slice(&secret_key.sk_to_pk().to_bytes()); - mock_header.message.header.transactions_root = - alloy::primitives::FixedBytes(EMPTY_TX_ROOT_HASH); + mock_header.message.header.transactions_root = EMPTY_TX_ROOT_HASH; assert_eq!( validate_header( @@ -425,7 +424,7 @@ mod tests { Err(ValidationError::BidTooLow { min: min_bid, got: U256::ZERO }) ); - mock_header.message.set_value(U256::from(1)); + mock_header.message.value = U256::from(1); mock_header.message.pubkey = pubkey; diff --git a/crates/signer/src/manager.rs b/crates/signer/src/manager.rs index ad0a1107..76430cc2 100644 --- a/crates/signer/src/manager.rs +++ b/crates/signer/src/manager.rs @@ -257,9 +257,9 @@ impl SigningManager { #[cfg(test)] mod tests { + use alloy::primitives::B256; use cb_common::signature::compute_signing_root; use lazy_static::lazy_static; - use tree_hash::Hash256; use super::*; @@ -338,17 +338,16 @@ mod tests { .unwrap(); let proxy_pk = signed_delegation.message.proxy; - let data_root = Hash256::random(); - let data_root_bytes = data_root.as_fixed_bytes(); + let data_root = B256::random(); let sig = signing_manager - .sign_proxy_bls(&proxy_pk.try_into().unwrap(), data_root_bytes) + .sign_proxy_bls(&proxy_pk.try_into().unwrap(), &data_root) .await .unwrap(); // Verify signature let domain = compute_domain(CHAIN, COMMIT_BOOST_DOMAIN); - let signing_root = compute_signing_root(data_root_bytes.tree_hash_root().0, domain); + let signing_root = compute_signing_root(data_root.tree_hash_root().0, domain); let validation_result = verify_bls_signature(&proxy_pk, &signing_root, &sig); @@ -417,17 +416,16 @@ mod tests { .unwrap(); let proxy_pk = signed_delegation.message.proxy; - let data_root = Hash256::random(); - let data_root_bytes = data_root.as_fixed_bytes(); + let data_root = B256::random(); let sig = signing_manager - .sign_proxy_ecdsa(&proxy_pk.try_into().unwrap(), data_root_bytes) + .sign_proxy_ecdsa(&proxy_pk.try_into().unwrap(), &data_root) .await .unwrap(); // Verify signature let domain = compute_domain(CHAIN, COMMIT_BOOST_DOMAIN); - let signing_root = compute_signing_root(data_root_bytes.tree_hash_root().0, domain); + let signing_root = compute_signing_root(data_root.tree_hash_root().0, domain); let validation_result = verify_ecdsa_signature(&proxy_pk, &signing_root, &sig); diff --git a/tests/src/mock_relay.rs b/tests/src/mock_relay.rs index 628be616..e9e42ca3 100644 --- a/tests/src/mock_relay.rs +++ b/tests/src/mock_relay.rs @@ -95,7 +95,7 @@ async fn handle_get_header( let mut response = GetHeaderResponse::default(); response.data.message.header.parent_hash = parent_hash; response.data.message.header.block_hash.0[0] = 1; - response.data.message.set_value(U256::from(10)); + response.data.message.value = U256::from(10); response.data.message.pubkey = blst_pubkey_to_alloy(&state.signer.sk_to_pk()); let object_root = response.data.message.tree_hash_root().0; response.data.signature = sign_builder_root(state.chain, &state.signer, object_root); diff --git a/tests/tests/payloads.rs b/tests/tests/payloads.rs index 38cd7160..8a2c1a68 100644 --- a/tests/tests/payloads.rs +++ b/tests/tests/payloads.rs @@ -1,24 +1,22 @@ -use std::fs; - use alloy::rpc::types::beacon::relay::ValidatorRegistration; -use cb_common::pbs::{SignedBlindedBeaconBlock, SubmitBlindedBlockResponse}; +use cb_common::{ + pbs::{SignedBlindedBeaconBlock, SubmitBlindedBlockResponse}, + utils::test_encode_decode, +}; #[test] fn test_registrations() { - let file = fs::read("data/registration_holesky.json").unwrap(); - let parsed = serde_json::from_slice::>(&file); - assert!(parsed.is_ok()); + let data = include_str!("../data/registration_holesky.json"); + test_encode_decode::>(&data); } #[test] fn test_signed_blinded_block() { - let file = fs::read("data/signed_blinded_block_holesky.json").unwrap(); - let parsed = serde_json::from_slice::(&file); - assert!(parsed.is_ok()); + let data = include_str!("../data/signed_blinded_block_holesky.json"); + test_encode_decode::(&data); } #[test] fn test_submit_block_response() { - let file = fs::read("data/submit_block_response_holesky.json").unwrap(); - let parsed = serde_json::from_slice::(&file); - assert!(parsed.is_ok()); + let data = include_str!("../data/submit_block_response_holesky.json"); + test_encode_decode::(&data); }