Skip to content

Commit

Permalink
wip: refactor to start cleaning things up
Browse files Browse the repository at this point in the history
  • Loading branch information
ralexstokes committed Aug 20, 2023
1 parent 445f580 commit 6dd6927
Show file tree
Hide file tree
Showing 11 changed files with 493 additions and 406 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions mev-build-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ license = "MIT OR Apache-2.0"

[dependencies]
tokio = { version = "1.0", features = ["full"] }
tokio-stream = "0.1.14"
tracing = "0.1"
futures = "0.3.21"
async-trait = "0.1.53"
Expand All @@ -24,6 +25,7 @@ ssz_rs = { workspace = true }

mev-rs = { path = "../mev-rs" }


revm = { workspace = true }
reth-payload-builder = { workspace = true }
reth-primitives = { workspace = true }
Expand Down
200 changes: 200 additions & 0 deletions mev-build-rs/src/mempool_builder/builder/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
use crate::mempool_builder::builder::{Error, RelayIndex};
use ethereum_consensus::{
capella::mainnet as spec,
crypto::{hash, SecretKey},
primitives::{BlsPublicKey, Bytes32, ExecutionAddress, Slot},
ssz::{ByteList, ByteVector},
state_transition::Context,
};
use ethers::signers::LocalWallet;
use mev_rs::{
signing::sign_builder_message,
types::{capella, BidTrace, ExecutionPayload, SignedBidSubmission},
};
use reth_primitives::{Bloom, Bytes, ChainSpec, SealedBlock, Withdrawal, H160, H256, U256};
use revm::primitives::{BlockEnv, CfgEnv};
use ssz_rs::prelude::*;
use std::sync::{Arc, Mutex};

pub type BuildIdentifier = Bytes32;

fn to_bytes32(value: H256) -> Bytes32 {
Bytes32::try_from(value.as_bytes()).unwrap()
}

fn to_bytes20(value: H160) -> ExecutionAddress {
ExecutionAddress::try_from(value.as_bytes()).unwrap()
}

fn to_byte_vector(value: Bloom) -> ByteVector<256> {
ByteVector::<256>::try_from(value.as_bytes()).unwrap()
}

fn to_u256(value: &U256) -> ssz_rs::U256 {
ssz_rs::U256::try_from_bytes_le(&value.to_le_bytes::<32>()).unwrap()
}

fn to_execution_payload(value: &SealedBlock) -> ExecutionPayload {
let hash = value.hash();
let header = &value.header;
let transactions = &value.body;
let withdrawals = &value.withdrawals;
let transactions = transactions
.iter()
.map(|t| spec::Transaction::try_from(t.envelope_encoded().as_ref()).unwrap())
.collect::<Vec<_>>();
let withdrawals = withdrawals
.as_ref()
.unwrap()
.iter()
.map(|w| spec::Withdrawal {
index: w.index as usize,
validator_index: w.validator_index as usize,
address: to_bytes20(w.address),
amount: w.amount,
})
.collect::<Vec<_>>();

let payload = capella::ExecutionPayload {
parent_hash: to_bytes32(header.parent_hash),
fee_recipient: to_bytes20(header.beneficiary),
state_root: to_bytes32(header.state_root),
receipts_root: to_bytes32(header.receipts_root),
logs_bloom: to_byte_vector(header.logs_bloom),
prev_randao: to_bytes32(header.mix_hash),
block_number: header.number,
gas_limit: header.gas_limit,
gas_used: header.gas_used,
timestamp: header.timestamp,
extra_data: ByteList::try_from(header.extra_data.as_ref()).unwrap(),
base_fee_per_gas: ssz_rs::U256::from(header.base_fee_per_gas.unwrap_or_default()),
block_hash: to_bytes32(hash),
transactions: TryFrom::try_from(transactions).unwrap(),
withdrawals: TryFrom::try_from(withdrawals).unwrap(),
};
ExecutionPayload::Capella(payload)
}

fn make_submission(
signing_key: &SecretKey,
builder_public_key: &BlsPublicKey,
context: &Context,
build_context: &BuildContext,
payload: &SealedBlock,
payment: &U256,
) -> Result<SignedBidSubmission, Error> {
let mut message = BidTrace {
slot: build_context.slot,
parent_hash: to_bytes32(payload.parent_hash),
block_hash: to_bytes32(payload.hash),
builder_public_key: builder_public_key.clone(),
proposer_public_key: build_context.proposer.clone(),
proposer_fee_recipient: build_context.proposer_fee_recipient.clone(),
gas_limit: payload.gas_limit,
gas_used: payload.gas_used,
value: to_u256(&payment),
};
let execution_payload = match to_execution_payload(payload) {
ExecutionPayload::Bellatrix(_) => unimplemented!(),
ExecutionPayload::Capella(payload) => payload,
ExecutionPayload::Deneb(_) => unimplemented!(),
};
let signature = sign_builder_message(&mut message, signing_key, context)?;
Ok(SignedBidSubmission { message, execution_payload, signature })
}

#[derive(Debug, Clone)]
pub struct BuildContext {
pub slot: Slot,
pub parent_hash: H256,
pub proposer: BlsPublicKey,
pub timestamp: u64,
pub proposer_fee_recipient: ExecutionAddress,
pub prev_randao: H256,
pub withdrawals: Vec<Withdrawal>,
pub relays: Vec<RelayIndex>,
pub chain_spec: Arc<ChainSpec>,
pub block_env: BlockEnv,
pub cfg_env: CfgEnv,
pub extra_data: Bytes,
pub parent_block: Arc<SealedBlock>,
pub builder_wallet: LocalWallet,
// Amount of gas to reserve after building a payload
// e.g. used for end-of-block proposer payments
pub gas_reserve: u64,
// Amount of the block's value to bid to the proposer
pub bid_percent: f64,
// Amount to add to the block's value to bid to the proposer
pub subsidy: U256,
}

pub fn compute_build_id(slot: Slot, parent_hash: H256, proposer: &BlsPublicKey) -> BuildIdentifier {
let mut data = Vec::with_capacity(88);
slot.serialize(&mut data).expect("can serialize");
parent_hash.serialize(&mut data).expect("can serialize");
proposer.serialize(&mut data).expect("can serialize");
hash(data)
}

impl BuildContext {
pub fn id(&self) -> BuildIdentifier {
compute_build_id(self.slot, self.parent_hash, &self.proposer)
}

pub fn base_fee(&self) -> u64 {
self.block_env.basefee.to::<u64>()
}

pub fn number(&self) -> u64 {
self.block_env.number.to::<u64>()
}

pub fn gas_limit(&self) -> u64 {
self.block_env.gas_limit.try_into().unwrap_or(u64::MAX)
}
}

#[derive(Debug)]
pub struct Build {
pub context: BuildContext,
pub state: Mutex<State>,
}

type State = PayloadWithPayments;

impl Build {
pub fn new(context: BuildContext, payload_with_payments: PayloadWithPayments) -> Self {
Self { context, state: Mutex::new(payload_with_payments) }
}

pub fn value(&self) -> U256 {
let state = self.state.lock().unwrap();
state.proposer_payment
}

pub fn prepare_bid(
&self,
secret_key: &SecretKey,
public_key: &BlsPublicKey,
context: &Context,
) -> Result<(SignedBidSubmission, U256), Error> {
let build_context = &self.context;
let state = self.state.lock().unwrap();
let payload = &state.payload;
let payment = &state.proposer_payment;
let builder_payment = state.builder_payment;
Ok((
make_submission(secret_key, public_key, context, build_context, payload, payment)?,
builder_payment,
))
}
}

#[derive(Debug)]
pub struct PayloadWithPayments {
// TODO: refactor here to `Option<_>`
// can migrate to "take" pattern and minimize lock contention
pub payload: SealedBlock,
pub proposer_payment: U256,
pub builder_payment: U256,
}
65 changes: 0 additions & 65 deletions mev-build-rs/src/mempool_builder/builder/compat.rs

This file was deleted.

Loading

0 comments on commit 6dd6927

Please sign in to comment.