Use only lighthouse types in the mock builder (#4793)

## Proposed Changes

- only use LH types to avoid build issues
- use warp instead of axum for the server to avoid importing the dep

## Additional Info

- wondering if we can move the `execution_layer/test_utils` to its own crate and import it as a dev dependency
- this would be made easier by separating out our engine API types into their own crate so we can use them in the test crate
- or maybe we can look into using reth types for the engine api if they are in their own crate


Co-authored-by: realbigsean <seananderson33@gmail.com>
This commit is contained in:
realbigsean 2023-10-03 17:59:28 +00:00
parent 8a1b77bf89
commit 7605494791
11 changed files with 411 additions and 573 deletions

206
Cargo.lock generated
View File

@ -195,15 +195,6 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "anvil-rpc"
version = "0.1.0"
source = "git+https://github.com/foundry-rs/foundry?rev=b45456717ffae1af65acdc71099f8cb95e6683a0#b45456717ffae1af65acdc71099f8cb95e6683a0"
dependencies = [
"serde",
"serde_json",
]
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.75" version = "1.0.75"
@ -311,28 +302,6 @@ dependencies = [
"event-listener", "event-listener",
] ]
[[package]]
name = "async-stream"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51"
dependencies = [
"async-stream-impl",
"futures-core",
"pin-project-lite",
]
[[package]]
name = "async-stream-impl"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.37",
]
[[package]] [[package]]
name = "async-trait" name = "async-trait"
version = "0.1.73" version = "0.1.73"
@ -509,24 +478,6 @@ version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
name = "beacon-api-client"
version = "0.1.0"
source = "git+https://github.com/ralexstokes/beacon-api-client?rev=93d7e8c#93d7e8c38fe9782c4862909663e7b57c44f805a9"
dependencies = [
"ethereum-consensus",
"http",
"itertools",
"reqwest",
"serde",
"serde_json",
"thiserror",
"tokio",
"tracing",
"tracing-subscriber",
"url",
]
[[package]] [[package]]
name = "beacon_chain" name = "beacon_chain"
version = "0.2.0" version = "0.2.0"
@ -1749,7 +1700,7 @@ dependencies = [
"aes-gcm", "aes-gcm",
"arrayvec", "arrayvec",
"delay_map", "delay_map",
"enr 0.9.1", "enr",
"fnv", "fnv",
"futures", "futures",
"hashlink 0.7.0", "hashlink 0.7.0",
@ -1895,7 +1846,6 @@ dependencies = [
"ff 0.12.1", "ff 0.12.1",
"generic-array", "generic-array",
"group 0.12.1", "group 0.12.1",
"pkcs8 0.9.0",
"rand_core 0.6.4", "rand_core 0.6.4",
"sec1 0.3.0", "sec1 0.3.0",
"subtle", "subtle",
@ -1931,25 +1881,6 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "enr"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26fa0a0be8915790626d5759eb51fe47435a8eac92c2f212bd2da9aa7f30ea56"
dependencies = [
"base64 0.13.1",
"bs58 0.4.0",
"bytes",
"hex",
"k256 0.11.6",
"log",
"rand",
"rlp",
"serde",
"sha3 0.10.8",
"zeroize",
]
[[package]] [[package]]
name = "enr" name = "enr"
version = "0.9.1" version = "0.9.1"
@ -2304,30 +2235,6 @@ dependencies = [
"tiny-keccak", "tiny-keccak",
] ]
[[package]]
name = "ethereum-consensus"
version = "0.1.1"
source = "git+https://github.com/ralexstokes/ethereum-consensus?rev=e380108#e380108d15fcc40349927fdf3d11c71f9edb67c2"
dependencies = [
"async-stream",
"blst",
"bs58 0.4.0",
"enr 0.6.2",
"hex",
"integer-sqrt",
"multiaddr 0.14.0",
"multihash 0.16.3",
"rand",
"serde",
"serde_json",
"serde_yaml",
"sha2 0.9.9",
"ssz_rs",
"thiserror",
"tokio",
"tokio-stream",
]
[[package]] [[package]]
name = "ethereum-types" name = "ethereum-types"
version = "0.12.1" version = "0.12.1"
@ -2565,12 +2472,10 @@ version = "0.1.0"
dependencies = [ dependencies = [
"arc-swap", "arc-swap",
"async-trait", "async-trait",
"axum",
"builder_client", "builder_client",
"bytes", "bytes",
"environment", "environment",
"eth2", "eth2",
"ethereum-consensus",
"ethereum_serde_utils", "ethereum_serde_utils",
"ethereum_ssz", "ethereum_ssz",
"ethers-core", "ethers-core",
@ -2580,13 +2485,11 @@ dependencies = [
"hash-db", "hash-db",
"hash256-std-hasher", "hash256-std-hasher",
"hex", "hex",
"hyper",
"jsonwebtoken", "jsonwebtoken",
"keccak-hash", "keccak-hash",
"lazy_static", "lazy_static",
"lighthouse_metrics", "lighthouse_metrics",
"lru 0.7.8", "lru 0.7.8",
"mev-rs",
"parking_lot 0.12.1", "parking_lot 0.12.1",
"pretty_reqwest_error", "pretty_reqwest_error",
"rand", "rand",
@ -2596,7 +2499,6 @@ dependencies = [
"serde_json", "serde_json",
"slog", "slog",
"slot_clock", "slot_clock",
"ssz_rs",
"ssz_types", "ssz_types",
"state_processing", "state_processing",
"strum", "strum",
@ -4007,7 +3909,7 @@ dependencies = [
"libp2p-swarm", "libp2p-swarm",
"libp2p-tcp", "libp2p-tcp",
"libp2p-yamux", "libp2p-yamux",
"multiaddr 0.18.0", "multiaddr",
"pin-project", "pin-project",
] ]
@ -4048,8 +3950,8 @@ dependencies = [
"instant", "instant",
"libp2p-identity", "libp2p-identity",
"log", "log",
"multiaddr 0.18.0", "multiaddr",
"multihash 0.19.1", "multihash",
"multistream-select", "multistream-select",
"once_cell", "once_cell",
"parking_lot 0.12.1", "parking_lot 0.12.1",
@ -4143,7 +4045,7 @@ dependencies = [
"ed25519-dalek", "ed25519-dalek",
"libsecp256k1", "libsecp256k1",
"log", "log",
"multihash 0.19.1", "multihash",
"p256", "p256",
"quick-protobuf", "quick-protobuf",
"rand", "rand",
@ -4222,8 +4124,8 @@ dependencies = [
"libp2p-core", "libp2p-core",
"libp2p-identity", "libp2p-identity",
"log", "log",
"multiaddr 0.18.0", "multiaddr",
"multihash 0.19.1", "multihash",
"once_cell", "once_cell",
"quick-protobuf", "quick-protobuf",
"rand", "rand",
@ -4805,27 +4707,6 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "mev-rs"
version = "0.3.0"
source = "git+https://github.com/ralexstokes/mev-rs?rev=216657016d5c0889b505857c89ae42c7aa2764af#216657016d5c0889b505857c89ae42c7aa2764af"
dependencies = [
"anvil-rpc",
"async-trait",
"axum",
"beacon-api-client",
"ethereum-consensus",
"hyper",
"parking_lot 0.12.1",
"reqwest",
"serde",
"serde_json",
"ssz_rs",
"thiserror",
"tokio",
"tracing",
]
[[package]] [[package]]
name = "migrations_internals" name = "migrations_internals"
version = "2.1.0" version = "2.1.0"
@ -4933,24 +4814,6 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389" checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389"
[[package]]
name = "multiaddr"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c580bfdd8803cce319b047d239559a22f809094aaea4ac13902a1fdcfcd4261"
dependencies = [
"arrayref",
"bs58 0.4.0",
"byteorder",
"data-encoding",
"multihash 0.16.3",
"percent-encoding",
"serde",
"static_assertions",
"unsigned-varint 0.7.2",
"url",
]
[[package]] [[package]]
name = "multiaddr" name = "multiaddr"
version = "0.18.0" version = "0.18.0"
@ -4962,7 +4825,7 @@ dependencies = [
"data-encoding", "data-encoding",
"libp2p-identity", "libp2p-identity",
"multibase", "multibase",
"multihash 0.19.1", "multihash",
"percent-encoding", "percent-encoding",
"serde", "serde",
"static_assertions", "static_assertions",
@ -4981,19 +4844,6 @@ dependencies = [
"data-encoding-macro", "data-encoding-macro",
] ]
[[package]]
name = "multihash"
version = "0.16.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c346cf9999c631f002d8f977c4eaeaa0e6386f16007202308d0b3757522c2cc"
dependencies = [
"core2",
"digest 0.10.7",
"multihash-derive",
"sha2 0.10.7",
"unsigned-varint 0.7.2",
]
[[package]] [[package]]
name = "multihash" name = "multihash"
version = "0.19.1" version = "0.19.1"
@ -5004,20 +4854,6 @@ dependencies = [
"unsigned-varint 0.7.2", "unsigned-varint 0.7.2",
] ]
[[package]]
name = "multihash-derive"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d6d4752e6230d8ef7adf7bd5d8c4b1f6561c1014c5ba9a37445ccefe18aa1db"
dependencies = [
"proc-macro-crate",
"proc-macro-error",
"proc-macro2",
"quote",
"syn 1.0.109",
"synstructure",
]
[[package]] [[package]]
name = "multistream-select" name = "multistream-select"
version = "0.13.0" version = "0.13.0"
@ -7349,31 +7185,6 @@ dependencies = [
"der 0.7.8", "der 0.7.8",
] ]
[[package]]
name = "ssz_rs"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "057291e5631f280978fa9c8009390663ca4613359fc1318e36a8c24c392f6d1f"
dependencies = [
"bitvec 1.0.1",
"hex",
"num-bigint",
"serde",
"sha2 0.9.9",
"ssz_rs_derive",
]
[[package]]
name = "ssz_rs_derive"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f07d54c4d01a1713eb363b55ba51595da15f6f1211435b71466460da022aa140"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]] [[package]]
name = "ssz_types" name = "ssz_types"
version = "0.5.4" version = "0.5.4"
@ -7881,7 +7692,6 @@ dependencies = [
"libc", "libc",
"mio", "mio",
"num_cpus", "num_cpus",
"parking_lot 0.12.1",
"pin-project-lite", "pin-project-lite",
"signal-hook-registry", "signal-hook-registry",
"socket2 0.5.4", "socket2 0.5.4",

View File

@ -136,7 +136,7 @@ r2d2 = "0.8"
rand = "0.8" rand = "0.8"
rayon = "1.7" rayon = "1.7"
regex = "1" regex = "1"
reqwest = { version = "0.11", default-features = false, features = ["blocking", "json", "stream", "rustls-tls"] } reqwest = { version = "0.11", default-features = false, features = ["blocking", "json", "stream", "rustls-tls", "native-tls-vendored"] }
ring = "0.16" ring = "0.16"
rusqlite = { version = "0.28", features = ["bundled"] } rusqlite = { version = "0.28", features = ["bundled"] }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
@ -156,7 +156,7 @@ superstruct = "0.6"
syn = "1" syn = "1"
sysinfo = "0.26" sysinfo = "0.26"
tempfile = "3" tempfile = "3"
tokio = { version = "1", features = ["rt-multi-thread", "sync"] } tokio = { version = "1", features = ["rt-multi-thread", "sync", "signal"] }
tokio-stream = { version = "0.1", features = ["sync"] } tokio-stream = { version = "0.1", features = ["sync"] }
tokio-util = { version = "0.6", features = ["codec", "compat", "time"] } tokio-util = { version = "0.6", features = ["codec", "compat", "time"] }
tree_hash = "0.5" tree_hash = "0.5"

View File

@ -17,8 +17,8 @@ use bls::get_withdrawal_credentials;
use execution_layer::{ use execution_layer::{
auth::JwtKey, auth::JwtKey,
test_utils::{ test_utils::{
ExecutionBlockGenerator, MockBuilder, MockBuilderServer, MockExecutionLayer, ExecutionBlockGenerator, MockBuilder, MockExecutionLayer, DEFAULT_JWT_SECRET,
DEFAULT_JWT_SECRET, DEFAULT_TERMINAL_BLOCK, DEFAULT_TERMINAL_BLOCK,
}, },
ExecutionLayer, ExecutionLayer,
}; };
@ -595,7 +595,10 @@ where
.execution_block_generator() .execution_block_generator()
} }
pub fn set_mock_builder(&mut self, beacon_url: SensitiveUrl) -> MockBuilderServer { pub fn set_mock_builder(
&mut self,
beacon_url: SensitiveUrl,
) -> impl futures::Future<Output = ()> {
let mock_el = self let mock_el = self
.mock_execution_layer .mock_execution_layer
.as_ref() .as_ref()
@ -604,7 +607,7 @@ where
let mock_el_url = SensitiveUrl::parse(mock_el.server.url().as_str()).unwrap(); let mock_el_url = SensitiveUrl::parse(mock_el.server.url().as_str()).unwrap();
// Create the builder, listening on a free port. // Create the builder, listening on a free port.
let (mock_builder, mock_builder_server) = MockBuilder::new_for_testing( let (mock_builder, (addr, mock_builder_server)) = MockBuilder::new_for_testing(
mock_el_url, mock_el_url,
beacon_url, beacon_url,
self.spec.clone(), self.spec.clone(),
@ -612,8 +615,7 @@ where
); );
// Set the builder URL in the execution layer now that its port is known. // Set the builder URL in the execution layer now that its port is known.
let builder_listen_addr = mock_builder_server.local_addr(); let port = addr.port();
let port = builder_listen_addr.port();
mock_el mock_el
.el .el
.set_builder_url( .set_builder_url(

View File

@ -41,11 +41,6 @@ lazy_static = { workspace = true }
ethers-core = { workspace = true } ethers-core = { workspace = true }
builder_client = { path = "../builder_client" } builder_client = { path = "../builder_client" }
fork_choice = { workspace = true } fork_choice = { workspace = true }
mev-rs = { git = "https://github.com/ralexstokes/mev-rs", rev = "216657016d5c0889b505857c89ae42c7aa2764af" }
axum = "0.6"
hyper = "0.14"
ethereum-consensus = { git = "https://github.com/ralexstokes/ethereum-consensus", rev = "e380108" }
ssz_rs = "0.9.0"
tokio-stream = { workspace = true } tokio-stream = { workspace = true }
strum = { workspace = true } strum = { workspace = true }
keccak-hash = "0.10.0" keccak-hash = "0.10.0"

View File

@ -1,49 +1,28 @@
use crate::test_utils::{DEFAULT_BUILDER_PAYLOAD_VALUE_WEI, DEFAULT_JWT_SECRET}; use crate::test_utils::{DEFAULT_BUILDER_PAYLOAD_VALUE_WEI, DEFAULT_JWT_SECRET};
use crate::{Config, ExecutionLayer, PayloadAttributes}; use crate::{Config, ExecutionLayer, PayloadAttributes};
use async_trait::async_trait;
use eth2::types::{BlockId, StateId, ValidatorId}; use eth2::types::{BlockId, StateId, ValidatorId};
use eth2::{BeaconNodeHttpClient, Timeouts}; use eth2::{BeaconNodeHttpClient, Timeouts};
pub use ethereum_consensus::state_transition::Context;
use ethereum_consensus::{
crypto::{SecretKey, Signature},
primitives::{BlsPublicKey, BlsSignature, ExecutionAddress, Hash32, Root, U256},
state_transition::Error,
};
use fork_choice::ForkchoiceUpdateParameters; use fork_choice::ForkchoiceUpdateParameters;
use mev_rs::{
blinded_block_provider::Server as BlindedBlockProviderServer,
signing::{sign_builder_message, verify_signed_builder_message},
types::{
bellatrix::{
BuilderBid as BuilderBidBellatrix, SignedBuilderBid as SignedBuilderBidBellatrix,
},
capella::{BuilderBid as BuilderBidCapella, SignedBuilderBid as SignedBuilderBidCapella},
BidRequest, BuilderBid, ExecutionPayload as ServerPayload, SignedBlindedBeaconBlock,
SignedBuilderBid, SignedValidatorRegistration,
},
Error as MevError,
};
use parking_lot::RwLock; use parking_lot::RwLock;
use sensitive_url::SensitiveUrl; use sensitive_url::SensitiveUrl;
use ssz::{Decode, Encode};
use ssz_rs::{Merkleized, SimpleSerialize};
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt::Debug; use std::fmt::Debug;
use std::net::Ipv4Addr; use std::future::Future;
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; 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::{BuilderBid, SignedBuilderBid};
use types::payload::BlindedPayloadRefMut;
use types::{ use types::{
Address, BeaconState, BlindedPayload, ChainSpec, EthSpec, ExecPayload, ForkName, Hash256, Slot, Address, BeaconState, BlindedPayload, ChainSpec, EthSpec, ExecPayload, ForkName,
Uint256, ForkVersionedResponse, Hash256, PublicKeyBytes, Signature, SignedBlindedBeaconBlock,
SignedRoot, SignedValidatorRegistrationData, Slot, Uint256,
}; };
use types::{ExecutionBlockHash, SecretKey};
pub type MockBuilderServer = axum::Server< use warp::{Filter, Rejection};
hyper::server::conn::AddrIncoming,
axum::routing::IntoMakeService<axum::routing::Router>,
>;
#[derive(Clone)] #[derive(Clone)]
pub enum Operation { pub enum Operation {
@ -58,121 +37,130 @@ pub enum Operation {
} }
impl Operation { impl Operation {
fn apply<B: BidStuff>(self, bid: &mut B) -> Result<(), MevError> { fn apply<E: EthSpec, B: BidStuff<E>>(self, bid: &mut B) {
match self { match self {
Operation::FeeRecipient(fee_recipient) => { Operation::FeeRecipient(fee_recipient) => bid.set_fee_recipient(fee_recipient),
*bid.fee_recipient_mut() = to_ssz_rs(&fee_recipient)? Operation::GasLimit(gas_limit) => bid.set_gas_limit(gas_limit as u64),
} Operation::Value(value) => bid.set_value(value),
Operation::GasLimit(gas_limit) => *bid.gas_limit_mut() = gas_limit as u64, Operation::ParentHash(parent_hash) => bid.set_parent_hash(parent_hash),
Operation::Value(value) => *bid.value_mut() = to_ssz_rs(&value)?, Operation::PrevRandao(prev_randao) => bid.set_prev_randao(prev_randao),
Operation::ParentHash(parent_hash) => *bid.parent_hash_mut() = to_ssz_rs(&parent_hash)?, Operation::BlockNumber(block_number) => bid.set_block_number(block_number as u64),
Operation::PrevRandao(prev_randao) => *bid.prev_randao_mut() = to_ssz_rs(&prev_randao)?, Operation::Timestamp(timestamp) => bid.set_timestamp(timestamp as u64),
Operation::BlockNumber(block_number) => *bid.block_number_mut() = block_number as u64, Operation::WithdrawalsRoot(root) => bid.set_withdrawals_root(root),
Operation::Timestamp(timestamp) => *bid.timestamp_mut() = timestamp as u64,
Operation::WithdrawalsRoot(root) => *bid.withdrawals_root_mut()? = to_ssz_rs(&root)?,
} }
Ok(())
} }
} }
#[derive(Debug)]
struct Custom(String);
impl warp::reject::Reject for Custom {}
// contains functions we need for BuilderBids.. not sure what to call this // contains functions we need for BuilderBids.. not sure what to call this
pub trait BidStuff { pub trait BidStuff<E: EthSpec> {
fn fee_recipient_mut(&mut self) -> &mut ExecutionAddress; fn set_fee_recipient(&mut self, fee_recipient_address: Address);
fn gas_limit_mut(&mut self) -> &mut u64; fn set_gas_limit(&mut self, gas_limit: u64);
fn value_mut(&mut self) -> &mut U256; fn set_value(&mut self, value: Uint256);
fn parent_hash_mut(&mut self) -> &mut Hash32; fn set_parent_hash(&mut self, parent_hash: Hash256);
fn prev_randao_mut(&mut self) -> &mut Hash32; fn set_prev_randao(&mut self, randao: Hash256);
fn block_number_mut(&mut self) -> &mut u64; fn set_block_number(&mut self, block_number: u64);
fn timestamp_mut(&mut self) -> &mut u64; fn set_timestamp(&mut self, timestamp: u64);
fn withdrawals_root_mut(&mut self) -> Result<&mut Root, MevError>; fn set_withdrawals_root(&mut self, withdrawals_root: Hash256);
fn sign_builder_message( fn sign_builder_message(&mut self, sk: &SecretKey, spec: &ChainSpec) -> Signature;
&mut self,
signing_key: &SecretKey,
context: &Context,
) -> Result<BlsSignature, Error>;
fn to_signed_bid(self, signature: BlsSignature) -> SignedBuilderBid; fn to_signed_bid(self, signature: Signature) -> SignedBuilderBid<E, BlindedPayload<E>>;
} }
impl BidStuff for BuilderBid { impl<E: EthSpec> BidStuff<E> for BuilderBid<E, BlindedPayload<E>> {
fn fee_recipient_mut(&mut self) -> &mut ExecutionAddress { fn set_fee_recipient(&mut self, fee_recipient: Address) {
match self { match self.header.to_mut() {
Self::Bellatrix(bid) => &mut bid.header.fee_recipient, BlindedPayloadRefMut::Merge(payload) => {
Self::Capella(bid) => &mut bid.header.fee_recipient, payload.execution_payload_header.fee_recipient = fee_recipient;
}
}
fn gas_limit_mut(&mut self) -> &mut u64 {
match self {
Self::Bellatrix(bid) => &mut bid.header.gas_limit,
Self::Capella(bid) => &mut bid.header.gas_limit,
}
}
fn value_mut(&mut self) -> &mut U256 {
match self {
Self::Bellatrix(bid) => &mut bid.value,
Self::Capella(bid) => &mut bid.value,
}
}
fn parent_hash_mut(&mut self) -> &mut Hash32 {
match self {
Self::Bellatrix(bid) => &mut bid.header.parent_hash,
Self::Capella(bid) => &mut bid.header.parent_hash,
}
}
fn prev_randao_mut(&mut self) -> &mut Hash32 {
match self {
Self::Bellatrix(bid) => &mut bid.header.prev_randao,
Self::Capella(bid) => &mut bid.header.prev_randao,
}
}
fn block_number_mut(&mut self) -> &mut u64 {
match self {
Self::Bellatrix(bid) => &mut bid.header.block_number,
Self::Capella(bid) => &mut bid.header.block_number,
}
}
fn timestamp_mut(&mut self) -> &mut u64 {
match self {
Self::Bellatrix(bid) => &mut bid.header.timestamp,
Self::Capella(bid) => &mut bid.header.timestamp,
}
}
fn withdrawals_root_mut(&mut self) -> Result<&mut Root, MevError> {
match self {
Self::Bellatrix(_) => Err(MevError::InvalidFork),
Self::Capella(bid) => Ok(&mut bid.header.withdrawals_root),
}
}
fn sign_builder_message(
&mut self,
signing_key: &SecretKey,
context: &Context,
) -> Result<Signature, Error> {
match self {
Self::Bellatrix(message) => sign_builder_message(message, signing_key, context),
Self::Capella(message) => sign_builder_message(message, signing_key, context),
}
}
fn to_signed_bid(self, signature: Signature) -> SignedBuilderBid {
match self {
Self::Bellatrix(message) => {
SignedBuilderBid::Bellatrix(SignedBuilderBidBellatrix { message, signature })
} }
Self::Capella(message) => { BlindedPayloadRefMut::Capella(payload) => {
SignedBuilderBid::Capella(SignedBuilderBidCapella { message, signature }) payload.execution_payload_header.fee_recipient = fee_recipient;
} }
} }
} }
fn set_gas_limit(&mut self, gas_limit: u64) {
match self.header.to_mut() {
BlindedPayloadRefMut::Merge(payload) => {
payload.execution_payload_header.gas_limit = gas_limit;
}
BlindedPayloadRefMut::Capella(payload) => {
payload.execution_payload_header.gas_limit = gas_limit;
}
}
}
fn set_value(&mut self, value: Uint256) {
self.value = value;
}
fn set_parent_hash(&mut self, parent_hash: Hash256) {
match self.header.to_mut() {
BlindedPayloadRefMut::Merge(payload) => {
payload.execution_payload_header.parent_hash =
ExecutionBlockHash::from_root(parent_hash);
}
BlindedPayloadRefMut::Capella(payload) => {
payload.execution_payload_header.parent_hash =
ExecutionBlockHash::from_root(parent_hash);
}
}
}
fn set_prev_randao(&mut self, prev_randao: Hash256) {
match self.header.to_mut() {
BlindedPayloadRefMut::Merge(payload) => {
payload.execution_payload_header.prev_randao = prev_randao;
}
BlindedPayloadRefMut::Capella(payload) => {
payload.execution_payload_header.prev_randao = prev_randao;
}
}
}
fn set_block_number(&mut self, block_number: u64) {
match self.header.to_mut() {
BlindedPayloadRefMut::Merge(payload) => {
payload.execution_payload_header.block_number = block_number;
}
BlindedPayloadRefMut::Capella(payload) => {
payload.execution_payload_header.block_number = block_number;
}
}
}
fn set_timestamp(&mut self, timestamp: u64) {
match self.header.to_mut() {
BlindedPayloadRefMut::Merge(payload) => {
payload.execution_payload_header.timestamp = timestamp;
}
BlindedPayloadRefMut::Capella(payload) => {
payload.execution_payload_header.timestamp = timestamp;
}
}
}
fn set_withdrawals_root(&mut self, withdrawals_root: Hash256) {
match self.header.to_mut() {
BlindedPayloadRefMut::Merge(_) => {
panic!("no withdrawals before capella")
}
BlindedPayloadRefMut::Capella(payload) => {
payload.execution_payload_header.withdrawals_root = withdrawals_root;
}
}
}
fn sign_builder_message(&mut self, sk: &SecretKey, spec: &ChainSpec) -> Signature {
let domain = spec.get_builder_domain();
let message = self.signing_root(domain);
sk.sign(message)
}
fn to_signed_bid(self, signature: Signature) -> SignedBuilderBid<E, BlindedPayload<E>> {
SignedBuilderBid {
message: self,
signature,
}
}
} }
#[derive(Clone)] #[derive(Clone)]
@ -180,8 +168,7 @@ pub struct MockBuilder<E: EthSpec> {
el: ExecutionLayer<E>, el: ExecutionLayer<E>,
beacon_client: BeaconNodeHttpClient, beacon_client: BeaconNodeHttpClient,
spec: ChainSpec, spec: ChainSpec,
context: Arc<Context>, val_registration_cache: Arc<RwLock<HashMap<PublicKeyBytes, SignedValidatorRegistrationData>>>,
val_registration_cache: Arc<RwLock<HashMap<BlsPublicKey, SignedValidatorRegistration>>>,
builder_sk: SecretKey, builder_sk: SecretKey,
operations: Arc<RwLock<Vec<Operation>>>, operations: Arc<RwLock<Vec<Operation>>>,
invalidate_signatures: Arc<RwLock<bool>>, invalidate_signatures: Arc<RwLock<bool>>,
@ -193,7 +180,7 @@ impl<E: EthSpec> MockBuilder<E> {
beacon_url: SensitiveUrl, beacon_url: SensitiveUrl,
spec: ChainSpec, spec: ChainSpec,
executor: TaskExecutor, executor: TaskExecutor,
) -> (Self, MockBuilderServer) { ) -> (Self, (SocketAddr, impl Future<Output = ()>)) {
let file = NamedTempFile::new().unwrap(); let file = NamedTempFile::new().unwrap();
let path = file.path().into(); let path = file.path().into();
std::fs::write(&path, hex::encode(DEFAULT_JWT_SECRET)).unwrap(); std::fs::write(&path, hex::encode(DEFAULT_JWT_SECRET)).unwrap();
@ -209,23 +196,14 @@ impl<E: EthSpec> MockBuilder<E> {
let el = let el =
ExecutionLayer::from_config(config, executor.clone(), executor.log().clone()).unwrap(); ExecutionLayer::from_config(config, executor.clone(), executor.log().clone()).unwrap();
// This should probably be done for all fields, we only update ones we are testing with so far.
let mut context = Context::for_mainnet();
context.terminal_total_difficulty = to_ssz_rs(&spec.terminal_total_difficulty).unwrap();
context.terminal_block_hash = to_ssz_rs(&spec.terminal_block_hash).unwrap();
context.terminal_block_hash_activation_epoch =
to_ssz_rs(&spec.terminal_block_hash_activation_epoch).unwrap();
let builder = MockBuilder::new( let builder = MockBuilder::new(
el, el,
BeaconNodeHttpClient::new(beacon_url, Timeouts::set_all(Duration::from_secs(1))), BeaconNodeHttpClient::new(beacon_url, Timeouts::set_all(Duration::from_secs(1))),
spec, spec,
context,
); );
let host: Ipv4Addr = Ipv4Addr::LOCALHOST; let host: Ipv4Addr = Ipv4Addr::LOCALHOST;
let port = 0; let port = 0;
let provider = BlindedBlockProviderServer::new(host, port, builder.clone()); let server = serve(host, port, builder.clone()).expect("mock builder server should start");
let server = provider.serve();
(builder, server) (builder, server)
} }
@ -233,15 +211,13 @@ impl<E: EthSpec> MockBuilder<E> {
el: ExecutionLayer<E>, el: ExecutionLayer<E>,
beacon_client: BeaconNodeHttpClient, beacon_client: BeaconNodeHttpClient,
spec: ChainSpec, spec: ChainSpec,
context: Context,
) -> Self { ) -> Self {
let sk = SecretKey::random(&mut rand::thread_rng()).unwrap(); let sk = SecretKey::random();
Self { Self {
el, el,
beacon_client, beacon_client,
// Should keep spec and context consistent somehow // Should keep spec and context consistent somehow
spec, spec,
context: Arc::new(context),
val_registration_cache: Arc::new(RwLock::new(HashMap::new())), val_registration_cache: Arc::new(RwLock::new(HashMap::new())),
builder_sk: sk, builder_sk: sk,
operations: Arc::new(RwLock::new(vec![])), operations: Arc::new(RwLock::new(vec![])),
@ -263,237 +239,282 @@ impl<E: EthSpec> MockBuilder<E> {
*self.invalidate_signatures.write() = false; *self.invalidate_signatures.write() = false;
} }
fn apply_operations<B: BidStuff>(&self, bid: &mut B) -> Result<(), MevError> { fn apply_operations<B: BidStuff<E>>(&self, bid: &mut B) {
let mut guard = self.operations.write(); let mut guard = self.operations.write();
while let Some(op) = guard.pop() { while let Some(op) = guard.pop() {
op.apply(bid)?; op.apply(bid);
} }
Ok(())
} }
} }
#[async_trait] pub fn serve<E: EthSpec>(
impl<E: EthSpec> mev_rs::BlindedBlockProvider for MockBuilder<E> { listen_addr: Ipv4Addr,
async fn register_validators( listen_port: u16,
&self, builder: MockBuilder<E>,
registrations: &mut [SignedValidatorRegistration], ) -> Result<(SocketAddr, impl Future<Output = ()>), crate::test_utils::Error> {
) -> Result<(), MevError> { let inner_ctx = builder.clone();
for registration in registrations { let ctx_filter = warp::any().map(move || inner_ctx.clone());
let pubkey = registration.message.public_key.clone();
let message = &mut registration.message;
verify_signed_builder_message(
message,
&registration.signature,
&pubkey,
&self.context,
)?;
self.val_registration_cache.write().insert(
registration.message.public_key.clone(),
registration.clone(),
);
}
Ok(()) let prefix = warp::path("eth")
} .and(warp::path("v1"))
.and(warp::path("builder"));
async fn fetch_best_bid(&self, bid_request: &BidRequest) -> Result<SignedBuilderBid, MevError> { let validators = prefix
let slot = Slot::new(bid_request.slot); .and(warp::path("validators"))
let fork = self.spec.fork_name_at_slot::<E>(slot); .and(warp::body::json())
let signed_cached_data = self .and(warp::path::end())
.val_registration_cache .and(ctx_filter.clone())
.read() .and_then(
.get(&bid_request.public_key) |registrations: Vec<SignedValidatorRegistrationData>, builder: MockBuilder<E>| async move {
.ok_or_else(|| convert_err("missing registration"))? for registration in registrations {
.clone(); if !registration.verify_signature(&builder.spec) {
let cached_data = signed_cached_data.message; return Err(reject("invalid signature"));
}
builder
.val_registration_cache
.write()
.insert(registration.message.pubkey, registration);
}
Ok(warp::reply())
},
);
let head = self let blinded_block = prefix
.beacon_client .and(warp::path("blinded_blocks"))
.get_beacon_blocks::<E>(BlockId::Head) .and(warp::body::json())
.await .and(warp::path::end())
.map_err(convert_err)? .and(ctx_filter.clone())
.ok_or_else(|| convert_err("missing head block"))?; .and_then(
|block: SignedBlindedBeaconBlock<E>, builder: MockBuilder<E>| async move {
let slot = block.slot();
let root = match block {
SignedBlindedBeaconBlock::Base(_) | types::SignedBeaconBlock::Altair(_) => {
return Err(reject("invalid fork"));
}
SignedBlindedBeaconBlock::Merge(block) => {
block.message.body.execution_payload.tree_hash_root()
}
SignedBlindedBeaconBlock::Capella(block) => {
block.message.body.execution_payload.tree_hash_root()
}
};
let block = head.data.message(); let fork_name = builder.spec.fork_name_at_slot::<E>(slot);
let head_block_root = block.tree_hash_root(); let payload = builder
let head_execution_hash = block .el
.body() .get_payload_by_root(&root)
.execution_payload() .ok_or_else(|| reject("missing payload for tx root"))?;
.map_err(convert_err)? let resp = ForkVersionedResponse {
.block_hash(); version: Some(fork_name),
if head_execution_hash != from_ssz_rs(&bid_request.parent_hash)? { data: payload,
return Err(custom_err(format!( };
"head mismatch: {} {}",
head_execution_hash, bid_request.parent_hash
)));
}
let finalized_execution_hash = self let json_payload = serde_json::to_string(&resp)
.beacon_client .map_err(|_| reject("coudn't serialize response"))?;
.get_beacon_blocks::<E>(BlockId::Finalized) Ok::<_, warp::reject::Rejection>(
.await warp::http::Response::builder()
.map_err(convert_err)? .status(200)
.ok_or_else(|| convert_err("missing finalized block"))? .body(
.data serde_json::to_string(&json_payload)
.message() .map_err(|_| reject("nvalid JSON"))?,
.body() )
.execution_payload() .unwrap(),
.map_err(convert_err)? )
.block_hash(); },
);
let justified_execution_hash = self let status = prefix
.beacon_client .and(warp::path("status"))
.get_beacon_blocks::<E>(BlockId::Justified) .then(|| async { warp::reply() });
.await
.map_err(convert_err)?
.ok_or_else(|| convert_err("missing finalized block"))?
.data
.message()
.body()
.execution_payload()
.map_err(convert_err)?
.block_hash();
let val_index = self let header = prefix
.beacon_client .and(warp::path("header"))
.get_beacon_states_validator_id( .and(warp::path::param::<Slot>().or_else(|_| async { Err(reject("Invalid slot")) }))
StateId::Head, .and(
&ValidatorId::PublicKey(from_ssz_rs(&cached_data.public_key)?), warp::path::param::<ExecutionBlockHash>()
) .or_else(|_| async { Err(reject("Invalid parent hash")) }),
.await )
.map_err(convert_err)? .and(
.ok_or_else(|| convert_err("missing validator from state"))? warp::path::param::<PublicKeyBytes>()
.data .or_else(|_| async { Err(reject("Invalid pubkey")) }),
.index; )
let fee_recipient = from_ssz_rs(&cached_data.fee_recipient)?; .and(warp::path::end())
let slots_since_genesis = slot.as_u64() - self.spec.genesis_slot.as_u64(); .and(ctx_filter.clone())
.and_then(
|slot: Slot,
parent_hash: ExecutionBlockHash,
pubkey: PublicKeyBytes,
builder: MockBuilder<E>| async move {
let fork = builder.spec.fork_name_at_slot::<E>(slot);
let signed_cached_data = builder
.val_registration_cache
.read()
.get(&pubkey)
.ok_or_else(|| reject("missing registration"))?
.clone();
let cached_data = signed_cached_data.message;
let genesis_time = self let head = builder
.beacon_client .beacon_client
.get_beacon_genesis() .get_beacon_blocks::<E>(BlockId::Head)
.await .await
.map_err(convert_err)? .map_err(|_| reject("couldn't get head"))?
.data .ok_or_else(|| reject("missing head block"))?;
.genesis_time;
let timestamp = (slots_since_genesis * self.spec.seconds_per_slot) + genesis_time;
let head_state: BeaconState<E> = self let block = head.data.message();
.beacon_client let head_block_root = block.tree_hash_root();
.get_debug_beacon_states(StateId::Head) let head_execution_hash = block
.await .body()
.map_err(convert_err)? .execution_payload()
.ok_or_else(|| custom_err("missing head state".to_string()))? .map_err(|_| reject("pre-merge block"))?
.data; .block_hash();
let prev_randao = head_state if head_execution_hash != parent_hash {
.get_randao_mix(head_state.current_epoch()) return Err(reject("head mismatch"));
.map_err(convert_err)?; }
let payload_attributes = match fork { let finalized_execution_hash = builder
ForkName::Merge => PayloadAttributes::new(timestamp, *prev_randao, fee_recipient, None), .beacon_client
// the withdrawals root is filled in by operations .get_beacon_blocks::<E>(BlockId::Finalized)
ForkName::Capella => { .await
PayloadAttributes::new(timestamp, *prev_randao, fee_recipient, Some(vec![])) .map_err(|_| reject("couldn't get finalized block"))?
} .ok_or_else(|| reject("missing finalized block"))?
ForkName::Base | ForkName::Altair => { .data
return Err(MevError::InvalidFork); .message()
} .body()
}; .execution_payload()
.map_err(|_| reject("pre-merge block"))?
.block_hash();
self.el let justified_execution_hash = builder
.insert_proposer(slot, head_block_root, val_index, payload_attributes.clone()) .beacon_client
.await; .get_beacon_blocks::<E>(BlockId::Justified)
.await
.map_err(|_| reject("couldn't get justified block"))?
.ok_or_else(|| reject("missing justified block"))?
.data
.message()
.body()
.execution_payload()
.map_err(|_| reject("pre-merge block"))?
.block_hash();
let forkchoice_update_params = ForkchoiceUpdateParameters { let val_index = builder
head_root: Hash256::zero(), .beacon_client
head_hash: None, .get_beacon_states_validator_id(StateId::Head, &ValidatorId::PublicKey(pubkey))
justified_hash: Some(justified_execution_hash), .await
finalized_hash: Some(finalized_execution_hash), .map_err(|_| reject("couldn't get validator"))?
}; .ok_or_else(|| reject("missing validator"))?
.data
.index;
let fee_recipient = cached_data.fee_recipient;
let slots_since_genesis = slot.as_u64() - builder.spec.genesis_slot.as_u64();
let payload = self let genesis_data = builder
.el .beacon_client
.get_full_payload_caching::<BlindedPayload<E>>( .get_beacon_genesis()
head_execution_hash, .await
&payload_attributes, .map_err(|_| reject("couldn't get beacon genesis"))?
forkchoice_update_params, .data;
fork, let genesis_time = genesis_data.genesis_time;
) let timestamp =
.await (slots_since_genesis * builder.spec.seconds_per_slot) + genesis_time;
.map_err(convert_err)?
.to_payload()
.to_execution_payload_header();
let json_payload = serde_json::to_string(&payload).map_err(convert_err)?; let head_state: BeaconState<E> = builder
let mut message = match fork { .beacon_client
ForkName::Capella => BuilderBid::Capella(BuilderBidCapella { .get_debug_beacon_states(StateId::Head)
header: serde_json::from_str(json_payload.as_str()).map_err(convert_err)?, .await
value: to_ssz_rs(&Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI))?, .map_err(|_| reject("couldn't get state"))?
public_key: self.builder_sk.public_key(), .ok_or_else(|| reject("missing state"))?
}), .data;
ForkName::Merge => BuilderBid::Bellatrix(BuilderBidBellatrix { let prev_randao = head_state
header: serde_json::from_str(json_payload.as_str()).map_err(convert_err)?, .get_randao_mix(head_state.current_epoch())
value: to_ssz_rs(&Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI))?, .map_err(|_| reject("couldn't get prev randao"))?;
public_key: self.builder_sk.public_key(),
}),
ForkName::Base | ForkName::Altair => return Err(MevError::InvalidFork),
};
*message.gas_limit_mut() = cached_data.gas_limit;
self.apply_operations(&mut message)?; let payload_attributes = match fork {
let mut signature = ForkName::Merge => {
message.sign_builder_message(&self.builder_sk, self.context.as_ref())?; PayloadAttributes::new(timestamp, *prev_randao, fee_recipient, None)
}
// the withdrawals root is filled in by operations
ForkName::Capella => {
PayloadAttributes::new(timestamp, *prev_randao, fee_recipient, Some(vec![]))
}
ForkName::Base | ForkName::Altair => {
return Err(reject("invalid fork"));
}
};
if *self.invalidate_signatures.read() { builder
signature = Signature::default(); .el
} .insert_proposer(slot, head_block_root, val_index, payload_attributes.clone())
.await;
Ok(message.to_signed_bid(signature)) let forkchoice_update_params = ForkchoiceUpdateParameters {
} head_root: Hash256::zero(),
head_hash: None,
justified_hash: Some(justified_execution_hash),
finalized_hash: Some(finalized_execution_hash),
};
async fn open_bid( let payload = builder
&self, .el
signed_block: &mut SignedBlindedBeaconBlock, .get_full_payload_caching::<BlindedPayload<E>>(
) -> Result<ServerPayload, MevError> { head_execution_hash,
let node = match signed_block { &payload_attributes,
SignedBlindedBeaconBlock::Bellatrix(block) => { forkchoice_update_params,
block.message.body.execution_payload_header.hash_tree_root() fork,
} )
SignedBlindedBeaconBlock::Capella(block) => { .await
block.message.body.execution_payload_header.hash_tree_root() .map_err(|_| reject("couldn't get payload"))?
} .to_payload()
} .to_execution_payload_header();
.map_err(convert_err)?;
let payload = self let mut message = BuilderBid {
.el header: BlindedPayload::from(payload),
.get_payload_by_root(&from_ssz_rs(&node)?) value: Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI),
.ok_or_else(|| convert_err("missing payload for tx root"))?; pubkey: builder.builder_sk.public_key().compress(),
_phantom_data: std::marker::PhantomData,
};
message.set_gas_limit(cached_data.gas_limit);
let json_payload = serde_json::to_string(&payload).map_err(convert_err)?; builder.apply_operations(&mut message);
serde_json::from_str(json_payload.as_str()).map_err(convert_err)
} let mut signature =
message.sign_builder_message(&builder.builder_sk, &builder.spec);
if *builder.invalidate_signatures.read() {
signature = Signature::empty();
}
let fork_name = builder
.spec
.fork_name_at_epoch(slot.epoch(E::slots_per_epoch()));
let signed_bid = SignedBuilderBid { message, signature };
let resp = ForkVersionedResponse {
version: Some(fork_name),
data: signed_bid,
};
let json_bid = serde_json::to_string(&resp)
.map_err(|_| reject("coudn't serialize signed bid"))?;
Ok::<_, Rejection>(
warp::http::Response::builder()
.status(200)
.body(json_bid)
.unwrap(),
)
},
);
let routes = warp::post()
.and(validators.or(blinded_block))
.or(warp::get().and(status).or(header))
.map(|reply| warp::reply::with_header(reply, "Server", "lighthouse-mock-builder-server"));
let (listening_socket, server) = warp::serve(routes)
.try_bind_ephemeral(SocketAddrV4::new(listen_addr, listen_port))
.expect("mock builder server should start");
Ok((listening_socket, server))
} }
pub fn from_ssz_rs<T: SimpleSerialize, U: Decode>(ssz_rs_data: &T) -> Result<U, MevError> { fn reject(msg: &'static str) -> Rejection {
U::from_ssz_bytes( warp::reject::custom(Custom(msg.to_string()))
ssz_rs::serialize(ssz_rs_data)
.map_err(convert_err)?
.as_ref(),
)
.map_err(convert_err)
}
pub fn to_ssz_rs<T: Encode, U: SimpleSerialize>(ssz_data: &T) -> Result<U, MevError> {
ssz_rs::deserialize::<U>(&ssz_data.as_ssz_bytes()).map_err(convert_err)
}
fn convert_err<E: Debug>(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 {
MevError::Consensus(ethereum_consensus::state_transition::Error::Io(
std::io::Error::new(std::io::ErrorKind::Other, s),
))
} }

View File

@ -25,7 +25,7 @@ use warp::{http::StatusCode, Filter, Rejection};
use crate::EngineCapabilities; use crate::EngineCapabilities;
pub use execution_block_generator::{generate_pow_block, Block, ExecutionBlockGenerator}; pub use execution_block_generator::{generate_pow_block, Block, ExecutionBlockGenerator};
pub use hook::Hook; pub use hook::Hook;
pub use mock_builder::{Context as MockBuilderContext, MockBuilder, MockBuilderServer, Operation}; pub use mock_builder::{MockBuilder, Operation};
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

@ -265,11 +265,7 @@ impl ApiTester {
// Start the mock builder service prior to building the chain out. // Start the mock builder service prior to building the chain out.
harness.runtime.task_executor.spawn( harness.runtime.task_executor.spawn(
async move { async move { mock_builder_server.await },
if let Err(e) = mock_builder_server.await {
panic!("error in mock builder server: {e:?}");
}
},
"mock_builder_server", "mock_builder_server",
); );

View File

@ -21,7 +21,7 @@ pub struct BuilderBid<E: EthSpec, Payload: AbstractExecPayload<E>> {
pub pubkey: PublicKeyBytes, pub pubkey: PublicKeyBytes,
#[serde(skip)] #[serde(skip)]
#[tree_hash(skip_hashing)] #[tree_hash(skip_hashing)]
_phantom_data: PhantomData<E>, pub _phantom_data: PhantomData<E>,
} }
impl<E: EthSpec, Payload: AbstractExecPayload<E>> SignedRoot for BuilderBid<E, Payload> {} impl<E: EthSpec, Payload: AbstractExecPayload<E>> SignedRoot for BuilderBid<E, Payload> {}

View File

@ -21,3 +21,17 @@ pub struct ValidatorRegistrationData {
} }
impl SignedRoot for ValidatorRegistrationData {} impl SignedRoot for ValidatorRegistrationData {}
impl SignedValidatorRegistrationData {
pub fn verify_signature(&self, spec: &ChainSpec) -> bool {
self.message
.pubkey
.decompress()
.map(|pubkey| {
let domain = spec.get_builder_domain();
let message = self.message.signing_root(domain);
self.signature.verify(&pubkey, message)
})
.unwrap_or(false)
}
}

View File

@ -56,7 +56,7 @@ itertools = { workspace = true }
monitoring_api = { workspace = true } monitoring_api = { workspace = true }
sensitive_url = { workspace = true } sensitive_url = { workspace = true }
task_executor = { workspace = true } task_executor = { workspace = true }
reqwest = { workspace = true } reqwest = { workspace = true, features = ["native-tls"] }
url = { workspace = true } url = { workspace = true }
malloc_utils = { workspace = true } malloc_utils = { workspace = true }
sysinfo = { workspace = true } sysinfo = { workspace = true }

View File

@ -2146,7 +2146,7 @@ async fn import_remotekey_web3signer_enabled() {
assert_eq!(tester.vals_total(), 1); assert_eq!(tester.vals_total(), 1);
assert_eq!(tester.vals_enabled(), 1); assert_eq!(tester.vals_enabled(), 1);
let vals = tester.initialized_validators.read(); let vals = tester.initialized_validators.read();
let web3_vals = vals.validator_definitions().clone(); let web3_vals = vals.validator_definitions();
// Import remotekeys. // Import remotekeys.
let import_res = tester let import_res = tester
@ -2164,7 +2164,7 @@ async fn import_remotekey_web3signer_enabled() {
assert_eq!(tester.vals_total(), 1); assert_eq!(tester.vals_total(), 1);
assert_eq!(tester.vals_enabled(), 1); assert_eq!(tester.vals_enabled(), 1);
let vals = tester.initialized_validators.read(); let vals = tester.initialized_validators.read();
let remote_vals = vals.validator_definitions().clone(); let remote_vals = vals.validator_definitions();
// Web3signer should not be overwritten since it is enabled. // Web3signer should not be overwritten since it is enabled.
assert!(web3_vals == remote_vals); assert!(web3_vals == remote_vals);