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

feat: small sidecar changes #151

Merged
merged 2 commits into from
Jul 25, 2024
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
5 changes: 5 additions & 0 deletions Justfile
merklefruit marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ sidecar-logs:
@id=$(docker ps -n 100 | grep sidecar | awk -F' ' '{print $1}') && \
docker logs -f $id

# show the logs for the bolt devnet beacon node
beacon-logs:
@id=$(docker ps -n 100 | grep 'cl-1-lighthouse-geth' | awk -F' ' '{print $1}') && \
docker logs -f $id
thedevbirb marked this conversation as resolved.
Show resolved Hide resolved

# show the logs for the bolt devnet for beacon node
beacon-logs:
@id=$(docker ps -n 100 | grep 'cl-1-lighthouse-geth' | awk -F' ' '{print $1}') && \
Expand Down
43 changes: 23 additions & 20 deletions bolt-sidecar/src/builder/compat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,13 @@ use ethereum_consensus::{
ssz::prelude::{ssz_rs, ByteList, ByteVector, HashTreeRoot, List},
types::mainnet::ExecutionPayload as ConsensusExecutionPayload,
};
use reth_primitives::{SealedBlock, SealedHeader, TransactionSigned, Withdrawals};
use reth_primitives::{SealedBlock, TransactionSigned, Withdrawals};

/// Compatibility: convert a sealed header into an ethereum-consensus execution payload header.
/// This requires recalculating the withdrals and transactions roots as SSZ instead of MPT roots.
pub(crate) fn to_execution_payload_header(
value: &SealedHeader,
sealed_block: &SealedBlock,
transactions: Vec<TransactionSigned>,
withdrawals: reth_primitives::Withdrawals,
) -> ConsensusExecutionPayloadHeader {
// Transactions and withdrawals are treated as opaque byte arrays in consensus types
let transactions_bytes = transactions
Expand All @@ -48,30 +47,34 @@ pub(crate) fn to_execution_payload_header(
let mut withdrawals_ssz: List<ConsensusWithdrawal, MAX_WITHDRAWALS_PER_PAYLOAD> =
List::default();

for w in withdrawals.iter() {
withdrawals_ssz.push(to_consensus_withdrawal(w));
if let Some(withdrawals) = sealed_block.withdrawals.as_ref() {
for w in withdrawals.iter() {
withdrawals_ssz.push(to_consensus_withdrawal(w));
}
}

let withdrawals_root = withdrawals_ssz
.hash_tree_root()
.expect("valid withdrawals root");

let header = &sealed_block.header;

ConsensusExecutionPayloadHeader {
parent_hash: to_bytes32(value.parent_hash),
fee_recipient: to_bytes20(value.beneficiary),
state_root: to_bytes32(value.state_root),
receipts_root: to_bytes32(value.receipts_root),
logs_bloom: to_byte_vector(value.logs_bloom),
prev_randao: to_bytes32(value.mix_hash),
block_number: value.number,
gas_limit: value.gas_limit,
gas_used: value.gas_used,
timestamp: value.timestamp,
extra_data: ByteList::try_from(value.extra_data.as_ref()).unwrap(),
base_fee_per_gas: ssz_rs::U256::from(value.base_fee_per_gas.unwrap_or_default()),
block_hash: to_bytes32(value.hash()),
blob_gas_used: value.blob_gas_used.unwrap_or_default(),
excess_blob_gas: value.excess_blob_gas.unwrap_or_default(),
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(header.hash()),
blob_gas_used: header.blob_gas_used.unwrap_or_default(),
excess_blob_gas: header.excess_blob_gas.unwrap_or_default(),
transactions_root,
withdrawals_root,
}
Expand Down
18 changes: 4 additions & 14 deletions bolt-sidecar/src/builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ pub enum BuilderError {

/// Local builder instance that can ingest a sealed header and
/// create the corresponding builder bid ready for the Builder API.
#[allow(missing_debug_implementations)]
#[derive(Debug)]
pub struct LocalBuilder {
/// BLS credentials for the local builder. We use this to sign the
/// payload bid submissions built by the sidecar.
Expand Down Expand Up @@ -118,27 +118,17 @@ impl LocalBuilder {
};

// 2. create a signed builder bid with the sealed block header we just created
let eth_header = compat::to_execution_payload_header(
&sealed_block.header,
transactions,
sealed_block.withdrawals.unwrap_or_default(),
);
let eth_header = compat::to_execution_payload_header(&sealed_block, transactions);

// 3. sign the bid with the local builder's BLS key
let signed_bid = self.create_signed_builder_bid(value, eth_header, kzg_commitments)?;

// 4. prepare a get_payload response for when the beacon node will ask for it
let Some(get_payload_res) =
GetPayloadResponse::try_from_execution_payload(&payload_and_blobs)
else {
return Err(BuilderError::Custom(
"Failed to build get_payload response: invalid fork version".to_string(),
));
};
let get_payload_response = GetPayloadResponse::from(payload_and_blobs);

self.payload_and_bid = Some(PayloadAndBid {
bid: signed_bid,
payload: get_payload_res,
payload: get_payload_response,
});

Ok(())
Expand Down
21 changes: 16 additions & 5 deletions bolt-sidecar/src/builder/payload_builder.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::fmt;

use alloy::{
eips::{calc_excess_blob_gas, calc_next_block_base_fee, eip1559::BaseFeeParams},
primitives::{Address, Bytes, B256, U256},
Expand Down Expand Up @@ -39,7 +41,6 @@ const DEFAULT_EXTRA_DATA: [u8; 20] = [
///
/// Find more information about this process & its reasoning here:
/// <https://github.com/chainbound/bolt/discussions/59>
#[allow(missing_debug_implementations)]
pub struct FallbackPayloadBuilder {
extra_data: Bytes,
fee_recipient: Address,
Expand Down Expand Up @@ -74,7 +75,7 @@ impl FallbackPayloadBuilder {
/// beacon chain, while others are calculated locally or from the
/// transactions themselves.
#[derive(Debug, Default)]
pub struct Context {
struct Context {
extra_data: Bytes,
base_fee: u64,
blob_gas_used: u64,
Expand All @@ -88,8 +89,7 @@ pub struct Context {
}

#[derive(Debug, Default)]
#[allow(missing_docs)]
pub struct Hints {
struct Hints {
pub gas_used: Option<u64>,
pub receipts_root: Option<B256>,
pub logs_bloom: Option<Bloom>,
Expand Down Expand Up @@ -357,7 +357,7 @@ pub(crate) fn parse_geth_response(error: &str) -> Option<String> {
}

/// Build a header with the given hints and context values.
pub(crate) fn build_header_with_hints_and_context(
fn build_header_with_hints_and_context(
latest_block: &Block,
hints: &Hints,
context: &Context,
Expand Down Expand Up @@ -393,6 +393,17 @@ pub(crate) fn build_header_with_hints_and_context(
}
}

impl fmt::Debug for FallbackPayloadBuilder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FallbackPayloadBuilder")
.field("extra_data", &self.extra_data)
.field("fee_recipient", &self.fee_recipient)
.field("engine_hinter", &self.engine_hinter)
.field("slot_time_in_seconds", &self.slot_time_in_seconds)
.finish()
}
}

#[cfg(test)]
mod tests {
use alloy::{
Expand Down
30 changes: 17 additions & 13 deletions bolt-sidecar/src/primitives/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,27 +170,17 @@ pub enum GetPayloadResponse {
Capella(ExecutionPayload),
#[serde(rename = "deneb")]
Deneb(PayloadAndBlobs),
#[serde(rename = "electra")]
Electra(PayloadAndBlobs),
}

impl GetPayloadResponse {
pub fn try_from_execution_payload(exec_payload: &PayloadAndBlobs) -> Option<Self> {
match exec_payload.execution_payload.version() {
Fork::Capella => Some(GetPayloadResponse::Capella(
exec_payload.execution_payload.clone(),
)),
Fork::Bellatrix => Some(GetPayloadResponse::Bellatrix(
exec_payload.execution_payload.clone(),
)),
Fork::Deneb => Some(GetPayloadResponse::Deneb(exec_payload.clone())),
_ => None,
}
}

pub fn block_hash(&self) -> &Hash32 {
match self {
GetPayloadResponse::Capella(payload) => payload.block_hash(),
GetPayloadResponse::Bellatrix(payload) => payload.block_hash(),
GetPayloadResponse::Deneb(payload) => payload.execution_payload.block_hash(),
GetPayloadResponse::Electra(payload) => payload.execution_payload.block_hash(),
}
}

Expand All @@ -199,6 +189,20 @@ impl GetPayloadResponse {
GetPayloadResponse::Capella(payload) => payload,
GetPayloadResponse::Bellatrix(payload) => payload,
GetPayloadResponse::Deneb(payload) => &payload.execution_payload,
GetPayloadResponse::Electra(payload) => &payload.execution_payload,
}
}
}

impl From<PayloadAndBlobs> for GetPayloadResponse {
fn from(payload_and_blobs: PayloadAndBlobs) -> Self {
match payload_and_blobs.execution_payload.version() {
Fork::Phase0 => GetPayloadResponse::Capella(payload_and_blobs.execution_payload),
Fork::Altair => GetPayloadResponse::Capella(payload_and_blobs.execution_payload),
Fork::Capella => GetPayloadResponse::Capella(payload_and_blobs.execution_payload),
Fork::Bellatrix => GetPayloadResponse::Bellatrix(payload_and_blobs.execution_payload),
Fork::Deneb => GetPayloadResponse::Deneb(payload_and_blobs),
Fork::Electra => GetPayloadResponse::Electra(payload_and_blobs),
}
}
}
Expand Down
Loading