Skip to content

Commit

Permalink
chore: cleanup types and warnings
Browse files Browse the repository at this point in the history
  • Loading branch information
merklefruit committed Jun 17, 2024
1 parent f6d4e88 commit 1c7f647
Show file tree
Hide file tree
Showing 19 changed files with 149 additions and 95 deletions.
1 change: 1 addition & 0 deletions bolt-sidecar/Cargo.lock

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

1 change: 1 addition & 0 deletions bolt-sidecar/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ alloy-consensus = { git = "https://github.com/alloy-rs/alloy", features = [
"k256",
] }
alloy-json-rpc = { git = "https://github.com/alloy-rs/alloy" }
alloy-network = { git = "https://github.com/alloy-rs/alloy" }
alloy-primitives = "0.7.1"
alloy-rlp = "0.3"

Expand Down
19 changes: 6 additions & 13 deletions bolt-sidecar/bin/sidecar.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
use bolt_sidecar::{
config::{Config, Opts},
crypto::bls::{from_bls_signature_to_consensus_signature, BLSSigner},
json_rpc::{api::ApiError, start_server},
primitives::{
constraint::{BatchedSignedConstraints, ConstraintsMessage, SignedConstraints},
ChainHead, CommitmentRequest, LocalPayloadFetcher, NoopPayloadFetcher,
BatchedSignedConstraints, ChainHead, CommitmentRequest, ConstraintsMessage,
LocalPayloadFetcher, NoopPayloadFetcher, SignedConstraints,
},
spec::ConstraintsApi,
start_builder_proxy,
state::{
fetcher::{StateClient, StateFetcher},
ExecutionState,
},
BuilderProxyConfig, MevBoostClient,
BuilderProxyConfig, Config, MevBoostClient, Opts,
};

use clap::Parser;
Expand Down Expand Up @@ -45,7 +44,7 @@ async fn main() -> eyre::Result<()> {
let builder_proxy_config = BuilderProxyConfig::default();

let (payload_tx, mut payload_rx) = mpsc::channel(1);
let payload_fetcher = LocalPayloadFetcher::new(payload_tx);
let _payload_fetcher = LocalPayloadFetcher::new(payload_tx);

let _builder_proxy = tokio::spawn(async move {
if let Err(e) = start_builder_proxy(NoopPayloadFetcher, builder_proxy_config).await {
Expand Down Expand Up @@ -76,17 +75,11 @@ async fn main() -> eyre::Result<()> {

// parse the request into constraints and sign them with the sidecar signer
// TODO: get the validator index from somewhere
let Ok(message) = ConstraintsMessage::build(0, request.slot, request.clone()) else {
tracing::error!("Failed to build constraints message, parsing error");
let _ = event
.response
.send(Err(ApiError::Custom("Internal server error".to_string())));
continue;
};
let message = ConstraintsMessage::build(0, request.slot, request.clone());

let signature = from_bls_signature_to_consensus_signature(signer.sign(&message));
let signed_constraints: BatchedSignedConstraints =
vec![SignedConstraints { message, signature }];
vec![SignedConstraints { message, signature: signature.to_string() }];

// TODO: fix retry logic
while let Err(e) = mevboost_client
Expand Down
4 changes: 4 additions & 0 deletions bolt-sidecar/src/api/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
/// Builder API endpoints
/// Reference: <https://ethereum.github.io/builder-specs/#/>
pub mod builder;

/// Sidecar API spec and error handling
pub mod spec;
1 change: 1 addition & 0 deletions bolt-sidecar/src/client/mevboost.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use crate::{
},
};

/// A client for interacting with the MEV-Boost API.
#[derive(Debug)]
pub struct MevBoostClient {
url: String,
Expand Down
1 change: 1 addition & 0 deletions bolt-sidecar/src/client/pubsub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use reqwest::Url;
pub struct PubsubClient(alloy::RpcClient<PubSubFrontend>);

impl PubsubClient {
/// Create a new `PubsubClient` with the given URL.
pub async fn new(url: &str) -> Result<Self, RpcError<TransportError>> {
let url = Url::from_str(url).unwrap();

Expand Down
3 changes: 2 additions & 1 deletion bolt-sidecar/src/client/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ use crate::primitives::AccountState;

/// An HTTP-based JSON-RPC client that supports batching. Implements all methods that are relevant
/// to Bolt state.
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct RpcClient(alloy::RpcClient<Http<Client>>);

impl RpcClient {
/// Create a new `RpcClient` with the given URL.
pub fn new(url: &str) -> Self {
let url = Url::from_str(url).unwrap();

Expand Down
6 changes: 6 additions & 0 deletions bolt-sidecar/src/crypto/bls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,23 @@ pub trait SignableBLS {
}

/// A BLS signer that can sign any type that implements the `Signable` trait.
#[derive(Clone, Debug)]
pub struct BLSSigner {
key: BlsSecretKey,
}

impl BLSSigner {
/// Create a new signer with the given secret key.
pub fn new(key: BlsSecretKey) -> Self {
Self { key }
}

/// Sign the object with the signer's key. Returns the signature.
pub fn sign<T: SignableBLS>(&self, obj: &T) -> Signature {
obj.sign(&self.key)
}

/// Verify the signature of the object with the given public key.
#[allow(dead_code)]
pub fn verify<T: SignableBLS>(
&self,
Expand All @@ -56,11 +60,13 @@ impl BLSSigner {
}
}

/// Compat: Convert a `blst` Signature to an `ethereum_consensus` Signature.
pub fn from_bls_signature_to_consensus_signature(sig: Signature) -> BlsSignature {
let bytes = sig.to_bytes();
BlsSignature::try_from(bytes.as_slice()).unwrap()
}

/// Create a random bls secret key (useful for testing)
pub fn random_bls_secret() -> BlsSecretKey {
let mut rng = rand::thread_rng();
let mut ikm = [0u8; 32];
Expand Down
1 change: 1 addition & 0 deletions bolt-sidecar/src/crypto/ecdsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub trait SignableECDSA {
}

/// A signer that can sign any type that implements `Signable{curve}` trait.
#[derive(Clone, Debug)]
pub struct ECDSASigner {
secp256k1_key: SecretKey,
}
Expand Down
2 changes: 2 additions & 0 deletions bolt-sidecar/src/crypto/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/// BLS12_381 signatures and verification functions.
pub mod bls;
pub use bls::{BLSSigner, SignableBLS};

/// ECDSA signatures and verification functions.
pub mod ecdsa;
2 changes: 2 additions & 0 deletions bolt-sidecar/src/json_rpc/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ impl CommitmentsRpc for JsonRpcApi {
}
}

/// Emit an event to the demo server webhook. This is only used for demo purposes.
#[allow(dead_code)]
fn emit_bolt_demo_event<T: Into<String>>(message: T) {
let msg = message.into();
tokio::spawn(async move {
Expand Down
5 changes: 4 additions & 1 deletion bolt-sidecar/src/json_rpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ use tokio::sync::mpsc;
use tracing::{error, info};
use warp::{http::Method, reject::Rejection, Filter};

/// JSON-RPC API implementation and handlers.
pub mod api;

/// JSON-RPC API specification and utilities.
mod spec;

use crate::config::Config;
use crate::Config;

use self::api::CommitmentsRpc;
use self::spec::{JsonRpcError, JsonRpcRequest, JsonRpcResponse};
Expand Down
33 changes: 25 additions & 8 deletions bolt-sidecar/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,37 @@
#![deny(unused_must_use, rust_2018_idioms)]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]

/// Builder API proxy and utilities
mod api;
pub use api::{
builder::{start_builder_proxy, BuilderProxyConfig},
spec,
};

mod client;
pub use client::{mevboost::MevBoostClient, rpc::RpcClient};

/// Common types and compatibility utilities
/// (To be refactored)
mod common;

/// Functionality for building local block templates that can
/// be used as a fallback for proposers. It's also used to keep
/// any intermediary state that is needed to simulate EVM execution
mod template;

/// Configuration and command-line argument parsing for the sidecar
pub mod config;
/// Configuration and command-line argument parsing
mod config;
pub use config::{Config, Opts};

/// Crypto utilities, including BLS and ECDSA
pub mod crypto;
/// JSON-RPC server and handlers for the sidecar

/// JSON-RPC server and handlers
pub mod json_rpc;
pub mod primitives;
pub mod state;

pub use api::builder::{start_builder_proxy, BuilderProxyConfig};
pub use client::{mevboost::MevBoostClient, rpc::RpcClient};
/// Primitive types and utilities
pub mod primitives;

pub use api::spec;
/// State management and fetching for EVM simulation
pub mod state;
90 changes: 45 additions & 45 deletions bolt-sidecar/src/primitives/constraint.rs
Original file line number Diff line number Diff line change
@@ -1,51 +1,11 @@
use alloy_eips::eip2718::Encodable2718;
use alloy_primitives::keccak256;
use secp256k1::Message;
use serde::{Deserialize, Serialize};

use crate::crypto::ecdsa::SignableECDSA;
use crate::crypto::{ecdsa::SignableECDSA, SignableBLS};

use super::Slot;

/// The API parameters to request an inclusion commitment for a given slot.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct InclusionRequestParams {
#[serde(flatten)]
pub message: InclusionRequestMessage,
pub signature: String,
}

/// The message to request an inclusion commitment for a given slot.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct InclusionRequestMessage {
pub slot: Slot,
pub tx: String,
pub index: Option<u64>,
}

/// What users have to sign to request an inclusion commitment.
/// We use the [SignableECDSA] trait to abstract over the signature verification step.
impl SignableECDSA for InclusionRequestMessage {
fn digest(&self) -> Message {
let mut data = Vec::new();
data.extend_from_slice(&self.slot.to_le_bytes());
data.extend_from_slice(self.tx.as_bytes());
data.extend_from_slice(&self.index.unwrap_or(0).to_le_bytes());

let hash = keccak256(data).0;
Message::from_digest_slice(&hash).expect("digest")
}
}

impl From<InclusionRequestParams> for Constraint {
fn from(params: InclusionRequestParams) -> Self {
Self {
tx: params.message.tx,
index: params.message.index,
}
}
}
use super::InclusionRequest;

/// What the proposer sidecar will need to sign to confirm the inclusion request.
impl SignableECDSA for ConstraintsMessage {
Expand All @@ -69,22 +29,30 @@ impl SignableECDSA for ConstraintsMessage {
/// that need to be forwarded to the PBS pipeline to inform block production.
pub type BatchedSignedConstraints = Vec<SignedConstraints>;

/// A container for a list of constraints and the signature of the proposer sidecar.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct SignedConstraints {
/// The constraints that need to be signed.
pub message: ConstraintsMessage,
/// The signature of the proposer sidecar.
pub signature: String,
}

/// A message that contains the constraints that need to be signed by the proposer sidecar.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct ConstraintsMessage {
/// The validator index of the proposer sidecar.
pub validator_index: u64,
/// The consensus slot at which the constraints are valid
pub slot: u64,
/// The constraints that need to be signed.
pub constraints: Vec<Constraint>,
}

impl ConstraintsMessage {
pub fn build(validator_index: u64, slot: u64, request: InclusionRequestParams) -> Self {
let constraints = vec![Constraint::from(request)];
/// Builds a constraints message from an inclusion request and metadata
pub fn build(validator_index: u64, slot: u64, request: InclusionRequest) -> Self {
let constraints = vec![Constraint::from_inclusion_request(request, None)];
Self {
validator_index,
slot,
Expand All @@ -93,13 +61,45 @@ impl ConstraintsMessage {
}
}

impl SignableBLS for ConstraintsMessage {
fn digest(&self) -> Vec<u8> {
let mut data = Vec::new();
data.extend_from_slice(&self.validator_index.to_le_bytes());
data.extend_from_slice(&self.slot.to_le_bytes());

let mut constraint_bytes = Vec::new();
for constraint in &self.constraints {
constraint_bytes.extend_from_slice(&constraint.as_bytes());
}
data.extend_from_slice(&constraint_bytes);

keccak256(data).0.to_vec()
}
}

/// A general constraint on block building.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct Constraint {
/// The raw transaction that needs to be included in the block
pub tx: String,
/// The optional index at which the transaction needs to be included in the block
pub index: Option<u64>,
}

impl Constraint {
/// Builds a constraint from an inclusion request and an optional index
pub fn from_inclusion_request(req: InclusionRequest, index: Option<u64>) -> Self {
let mut encoded_tx = Vec::new();
req.tx.encode_2718(&mut encoded_tx);

Self {
tx: format!("0x{}", hex::encode(encoded_tx)),
index,
}
}

/// Converts the constraint to a byte representation useful for signing
/// TODO: remove if we go with SSZ
pub fn as_bytes(&self) -> Vec<u8> {
let mut data = Vec::new();
data.extend_from_slice(self.tx.as_bytes());
Expand Down
8 changes: 7 additions & 1 deletion bolt-sidecar/src/primitives/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@ use ethereum_consensus::{
};
use tokio::sync::{mpsc, oneshot};

/// Commitment types, received by users wishing to receive preconfirmations.
pub mod commitment;
pub use commitment::{CommitmentRequest, InclusionRequest};

/// Constraint types, signed by proposers and sent along the PBS pipeline
/// for validation.
pub mod constraint;
pub use constraint::BatchedSignedConstraints;
pub use constraint::{BatchedSignedConstraints, ConstraintsMessage, SignedConstraints};

/// Transaction primitives and utilities.
pub mod transaction;
pub use transaction::TxInfo;

Expand Down Expand Up @@ -211,6 +215,7 @@ impl<'de> serde::Deserialize<'de> for GetPayloadResponse {
}
}

/// A struct representing the current chain head.
#[derive(Debug, Clone)]
pub struct ChainHead {
/// The current slot number.
Expand All @@ -220,6 +225,7 @@ pub struct ChainHead {
}

impl ChainHead {
/// Create a new ChainHead instance.
pub fn new(slot: u64, head: u64) -> Self {
Self {
slot: Arc::new(AtomicU64::new(slot)),
Expand Down
Loading

0 comments on commit 1c7f647

Please sign in to comment.