Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

uses polymorphic types #151

Merged
merged 7 commits into from
Oct 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
791 changes: 384 additions & 407 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ default-members = ["bin/mev"]
version = "0.3.0"

[workspace.dependencies]
ethereum-consensus = { git = "https://github.com/ralexstokes/ethereum-consensus", rev = "afbf74216b49d30562aa3e966b9daa9aa416d534" }
beacon-api-client = { git = "https://github.com/ralexstokes/ethereum-consensus", rev = "afbf74216b49d30562aa3e966b9daa9aa416d534" }
ethereum-consensus = { git = "https://github.com/ralexstokes/ethereum-consensus", rev = "e810cecbb113de66aeedae6dcde2a69cd284f88d" }
beacon-api-client = { git = "https://github.com/ralexstokes/ethereum-consensus", rev = "e810cecbb113de66aeedae6dcde2a69cd284f88d" }

reth-payload-builder = { git = "https://github.com/paradigmxyz/reth", rev = "1b16d804ef01f4ec3c25e7986381c22739c105b9" }
reth-primitives = { git = "https://github.com/paradigmxyz/reth", rev = "1b16d804ef01f4ec3c25e7986381c22739c105b9" }
Expand Down
21 changes: 13 additions & 8 deletions mev-boost-rs/src/relay_mux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ const PROPOSAL_TOLERANCE_DELAY: Slot = 1;
const FETCH_BEST_BID_TIME_OUT_SECS: u64 = 1;

fn bid_key_from(signed_block: &SignedBlindedBeaconBlock, public_key: &BlsPublicKey) -> BidRequest {
let slot = signed_block.slot();
let parent_hash = signed_block.parent_hash().clone();
let slot = *signed_block.message().slot();
let parent_hash =
signed_block.message().body().execution_payload_header().parent_hash().clone();

BidRequest { slot, parent_hash, public_key: public_key.clone() }
}
Expand All @@ -35,9 +36,10 @@ fn validate_bid(
public_key: &BlsPublicKey,
context: &Context,
) -> Result<(), Error> {
if bid.public_key() != public_key {
let bid_public_key = &bid.message.public_key;
if bid_public_key != public_key {
return Err(Error::BidPublicKeyMismatch {
bid: bid.public_key().clone(),
bid: bid_public_key.clone(),
relay: public_key.clone(),
})
}
Expand Down Expand Up @@ -169,7 +171,7 @@ impl BlindedBlockProvider for RelayMux {

// TODO: change `value` so it does the copy internally
let mut best_bid_indices =
select_best_bids(bids.iter().map(|(_, bid)| bid.value().clone()).enumerate());
select_best_bids(bids.iter().map(|(_, bid)| bid.message.value.clone()).enumerate());

// if multiple distinct bids with same bid value, break tie by randomly picking one
let mut rng = rand::thread_rng();
Expand All @@ -179,12 +181,12 @@ impl BlindedBlockProvider for RelayMux {
best_bid_indices.split_first().expect("there is at least one bid");

let (best_relay, best_bid) = &bids[*best_bid_index];
let best_block_hash = best_bid.block_hash();
let best_block_hash = best_bid.message.header.block_hash();

let mut best_relays = vec![best_relay.clone()];
for bid_index in rest {
let (relay, bid) = &bids[*bid_index];
if bid.block_hash() == best_block_hash {
if bid.message.header.block_hash() == best_block_hash {
best_relays.push(relay.clone());
}
}
Expand Down Expand Up @@ -227,7 +229,10 @@ impl BlindedBlockProvider for RelayMux {
.collect::<Vec<_>>()
.await;

let expected_block_hash = signed_block.block_hash();
let block = signed_block.message();
let block_body = block.body();
let payload_header = block_body.execution_payload_header();
let expected_block_hash = payload_header.block_hash();
for (relay, response) in responses.into_iter() {
match response {
Ok(payload) => {
Expand Down
105 changes: 105 additions & 0 deletions mev-boost-rs/tests/identity_builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use async_trait::async_trait;
use ethereum_consensus::{
bellatrix::mainnet as bellatrix,
builder::{SignedValidatorRegistration, ValidatorRegistration},
capella::mainnet as capella,
crypto::SecretKey,
primitives::{BlsPublicKey, Slot, U256},
state_transition::Context,
};
use mev_rs::{
blinded_block_provider::BlindedBlockProvider,
signing::sign_builder_message,
types::{
BidRequest, BuilderBid, ExecutionPayload, ExecutionPayloadHeader, SignedBlindedBeaconBlock,
SignedBuilderBid,
},
Error,
};
use std::{
collections::HashMap,
sync::{Arc, Mutex},
};

#[derive(Default, Clone)]
pub struct IdentityBuilder {
signing_key: SecretKey,
public_key: BlsPublicKey,
context: Arc<Context>,
bids: Arc<Mutex<HashMap<Slot, ExecutionPayload>>>,
registrations: Arc<Mutex<HashMap<BlsPublicKey, ValidatorRegistration>>>,
}

impl IdentityBuilder {
pub fn new(context: Context) -> Self {
let signing_key = SecretKey::try_from([1u8; 32].as_ref()).unwrap();
let public_key = signing_key.public_key();
Self { signing_key, public_key, context: Arc::new(context), ..Default::default() }
}
}

#[async_trait]
impl BlindedBlockProvider for IdentityBuilder {
async fn register_validators(
&self,
registrations: &mut [SignedValidatorRegistration],
) -> Result<(), Error> {
let mut state = self.registrations.lock().unwrap();
for registration in registrations {
let registration = &registration.message;
let public_key = registration.public_key.clone();
state.insert(public_key, registration.clone());
}
Ok(())
}

async fn fetch_best_bid(
&self,
BidRequest { slot, parent_hash, public_key }: &BidRequest,
) -> Result<SignedBuilderBid, Error> {
let capella_fork_slot = self.context.capella_fork_epoch * self.context.slots_per_epoch;
let state = self.registrations.lock().unwrap();
let preferences = state.get(public_key).unwrap();
let value = U256::from(1337);
let (payload, header) = if *slot < capella_fork_slot {
let mut payload = bellatrix::ExecutionPayload {
parent_hash: parent_hash.clone(),
fee_recipient: preferences.fee_recipient.clone(),
gas_limit: preferences.gas_limit,
..Default::default()
};
let header = ExecutionPayloadHeader::Bellatrix(
bellatrix::ExecutionPayloadHeader::try_from(&mut payload).unwrap(),
);
(ExecutionPayload::Bellatrix(payload), header)
} else {
let mut payload = capella::ExecutionPayload {
parent_hash: parent_hash.clone(),
fee_recipient: preferences.fee_recipient.clone(),
gas_limit: preferences.gas_limit,
..Default::default()
};
let header = ExecutionPayloadHeader::Capella(
capella::ExecutionPayloadHeader::try_from(&mut payload).unwrap(),
);
(ExecutionPayload::Capella(payload), header)
};

let mut builder_bid = BuilderBid { header, value, public_key: self.public_key.clone() };
let signature =
sign_builder_message(&mut builder_bid, &self.signing_key, &self.context).unwrap();
let signed_builder_bid = SignedBuilderBid { message: builder_bid, signature };
let mut state = self.bids.lock().unwrap();
state.insert(*slot, payload);
Ok(signed_builder_bid)
}

async fn open_bid(
&self,
signed_block: &mut SignedBlindedBeaconBlock,
) -> Result<ExecutionPayload, Error> {
let slot = *signed_block.message().slot();
let state = self.bids.lock().unwrap();
Ok(state.get(&slot).cloned().unwrap())
}
}
151 changes: 23 additions & 128 deletions mev-boost-rs/tests/integration.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,27 @@
use async_trait::async_trait;
mod identity_builder;

use beacon_api_client::Client as ApiClient;
use ethereum_consensus::{
bellatrix::mainnet as bellatrix,
builder::{SignedValidatorRegistration, ValidatorRegistration},
capella::mainnet as capella,
crypto::SecretKey,
phase0::mainnet::{compute_domain, Validator},
primitives::{BlsPublicKey, DomainType, ExecutionAddress, Hash32, Root, Slot, U256},
primitives::{DomainType, ExecutionAddress, Hash32, Root},
signing::sign_with_domain,
state_transition::{Context, Forks},
state_transition::Context,
Fork,
};
use identity_builder::*;
use mev_boost_rs::{Config, Service};
use mev_rs::{
blinded_block_provider::{BlindedBlockProvider, Client as RelayClient, Server as RelayServer},
blinded_block_provider::{Client as RelayClient, Server as RelayServer},
signing::sign_builder_message,
types::{
bellatrix as bellatrix_builder, capella as capella_builder, BidRequest, ExecutionPayload,
SignedBlindedBeaconBlock, SignedBuilderBid,
},
Error,
types::{BidRequest, SignedBlindedBeaconBlock},
};
use rand::seq::SliceRandom;
use std::{
collections::HashMap,
net::Ipv4Addr,
sync::{Arc, Mutex},
time::{SystemTime, UNIX_EPOCH},
};
use url::Url;
Expand Down Expand Up @@ -67,96 +64,6 @@ fn create_proposers<R: rand::Rng>(rng: &mut R, count: usize) -> Vec<Proposer> {
.collect()
}

#[derive(Default, Clone)]
pub struct IdentityBuilder {
signing_key: SecretKey,
public_key: BlsPublicKey,
context: Arc<Context>,
bids: Arc<Mutex<HashMap<Slot, ExecutionPayload>>>,
registrations: Arc<Mutex<HashMap<BlsPublicKey, ValidatorRegistration>>>,
}

impl IdentityBuilder {
fn new(context: Context) -> Self {
let signing_key = SecretKey::try_from([1u8; 32].as_ref()).unwrap();
let public_key = signing_key.public_key();
Self { signing_key, public_key, context: Arc::new(context), ..Default::default() }
}
}

#[async_trait]
impl BlindedBlockProvider for IdentityBuilder {
async fn register_validators(
&self,
registrations: &mut [SignedValidatorRegistration],
) -> Result<(), Error> {
let mut state = self.registrations.lock().unwrap();
for registration in registrations {
let registration = &registration.message;
let public_key = registration.public_key.clone();
state.insert(public_key, registration.clone());
}
Ok(())
}

async fn fetch_best_bid(
&self,
BidRequest { slot, parent_hash, public_key }: &BidRequest,
) -> Result<SignedBuilderBid, Error> {
let capella_fork_slot = self.context.capella_fork_epoch * self.context.slots_per_epoch;
let state = self.registrations.lock().unwrap();
let preferences = state.get(public_key).unwrap();
let value = U256::from(1337);
let (payload, signed_builder_bid) = if *slot < capella_fork_slot {
let mut inner = bellatrix::ExecutionPayload {
parent_hash: parent_hash.clone(),
fee_recipient: preferences.fee_recipient.clone(),
gas_limit: preferences.gas_limit,
..Default::default()
};
let header = bellatrix::ExecutionPayloadHeader::try_from(&mut inner).unwrap();
let payload = ExecutionPayload::Bellatrix(inner);
let mut inner = bellatrix_builder::BuilderBid {
header,
value,
public_key: self.public_key.clone(),
};
let signature =
sign_builder_message(&mut inner, &self.signing_key, &self.context).unwrap();
let inner = bellatrix_builder::SignedBuilderBid { message: inner, signature };
(payload, SignedBuilderBid::Bellatrix(inner))
} else {
let mut inner = capella::ExecutionPayload {
parent_hash: parent_hash.clone(),
fee_recipient: preferences.fee_recipient.clone(),
gas_limit: preferences.gas_limit,
..Default::default()
};
let header = capella::ExecutionPayloadHeader::try_from(&mut inner).unwrap();
let payload = ExecutionPayload::Capella(inner);
let mut inner =
capella_builder::BuilderBid { header, value, public_key: self.public_key.clone() };
let signature =
sign_builder_message(&mut inner, &self.signing_key, &self.context).unwrap();
let inner = capella_builder::SignedBuilderBid { message: inner, signature };
(payload, SignedBuilderBid::Capella(inner))
};

let mut state = self.bids.lock().unwrap();
state.insert(*slot, payload);
Ok(signed_builder_bid)
}

async fn open_bid(
&self,
signed_block: &mut SignedBlindedBeaconBlock,
) -> Result<ExecutionPayload, Error> {
let slot = signed_block.slot();
let state = self.bids.lock().unwrap();
Ok(state.get(&slot).cloned().unwrap())
}
}

#[tokio::test]
async fn test_end_to_end() {
setup_logging();
Expand Down Expand Up @@ -231,10 +138,10 @@ async fn propose_block(
context: &Context,
genesis_validators_root: &Root,
) {
let fork = if shuffling_index == 0 { Forks::Bellatrix } else { Forks::Capella };
let fork = if shuffling_index == 0 { Fork::Bellatrix } else { Fork::Capella };
let current_slot = match fork {
Forks::Bellatrix => 32 + context.bellatrix_fork_epoch * context.slots_per_epoch,
Forks::Capella => 32 + context.capella_fork_epoch * context.slots_per_epoch,
Fork::Bellatrix => 32 + context.bellatrix_fork_epoch * context.slots_per_epoch,
Fork::Capella => 32 + context.capella_fork_epoch * context.slots_per_epoch,
_ => unimplemented!(),
};
let parent_hash = Hash32::try_from([shuffling_index as u8; 32].as_ref()).unwrap();
Expand All @@ -245,17 +152,14 @@ async fn propose_block(
public_key: proposer.validator.public_key.clone(),
};
let signed_bid = beacon_node.fetch_best_bid(&request).await.unwrap();
let bid_parent_hash = signed_bid.parent_hash();
let bid_parent_hash = signed_bid.message.header.parent_hash();
assert_eq!(bid_parent_hash, &parent_hash);

let signed_block = match fork {
Forks::Bellatrix => {
let bid = match signed_bid {
SignedBuilderBid::Bellatrix(bid) => bid,
_ => unimplemented!(),
};
Fork::Bellatrix => {
let header = signed_bid.message.header.bellatrix().unwrap().clone();
let beacon_block_body = bellatrix::BlindedBeaconBlockBody {
execution_payload_header: bid.message.header,
execution_payload_header: header,
..Default::default()
};
let mut beacon_block = bellatrix::BlindedBeaconBlock {
Expand All @@ -278,13 +182,10 @@ async fn propose_block(
bellatrix::SignedBlindedBeaconBlock { message: beacon_block, signature };
SignedBlindedBeaconBlock::Bellatrix(signed_block)
}
Forks::Capella => {
let bid = match signed_bid {
SignedBuilderBid::Capella(bid) => bid,
_ => unimplemented!(),
};
Fork::Capella => {
let header = signed_bid.message.header.capella().unwrap().clone();
let beacon_block_body = capella::BlindedBeaconBlockBody {
execution_payload_header: bid.message.header,
execution_payload_header: header,
..Default::default()
};
let mut beacon_block = capella::BlindedBeaconBlock {
Expand Down Expand Up @@ -314,17 +215,11 @@ async fn propose_block(

let payload = beacon_node.open_bid(&signed_block).await.unwrap();

match payload {
ExecutionPayload::Bellatrix(payload) => {
assert_eq!(payload.parent_hash, parent_hash);
assert_eq!(payload.fee_recipient, proposer.fee_recipient);
}
ExecutionPayload::Capella(payload) => {
assert_eq!(payload.parent_hash, parent_hash);
assert_eq!(payload.fee_recipient, proposer.fee_recipient);
}
_ => unimplemented!(),
}
let payload_parent_hash = payload.parent_hash();
assert_eq!(payload_parent_hash, &parent_hash);

let payload_fee_recipient = payload.fee_recipient();
assert_eq!(payload_fee_recipient, &proposer.fee_recipient);

beacon_node.check_status().await.unwrap();
}
Loading