Skip to content

refactor: trim some dead code, simplify auth #73

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

Merged
merged 5 commits into from
May 8, 2025
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
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "zenith-builder-example"
name = "builder"
version = "0.1.1"
description = "Zenith Builder Example"
description = "signet builder example"

edition = "2024"
rust-version = "1.85"
Expand Down
21 changes: 12 additions & 9 deletions bin/builder.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
use builder::{
config::BuilderConfig,
service::serve_builder_with_span,
service::serve_builder,
tasks::{
block::Simulator, bundler, metrics::MetricsTask, oauth::Authenticator, submit::SubmitTask,
tx_poller,
},
};
use init4_bin_base::{deps::tracing, utils::calc::SlotCalculator};
use signet_sim::SimCache;
use signet_types::SlotCalculator;
use std::sync::Arc;
use tokio::select;
use tracing::info_span;

// Note: Must be set to `multi_thread` to support async tasks.
// See: https://docs.rs/tokio/latest/tokio/attr.main.html
#[tokio::main(flavor = "multi_thread")]
async fn main() -> eyre::Result<()> {
let _guard = init4_bin_base::init4();

let span = tracing::info_span!("zenith-builder");
let init_span_guard = info_span!("builder initialization");

let config = BuilderConfig::load_from_env()?.clone();
let constants = config.load_pecorino_constants();
let authenticator = Authenticator::new(&config);
let authenticator = Authenticator::new(&config)?;

let (host_provider, ru_provider, sequencer_signer) = tokio::try_join!(
config.connect_host_provider(),
Expand All @@ -35,7 +35,7 @@ async fn main() -> eyre::Result<()> {
let (tx_channel, metrics_jh) = metrics.spawn();

let submit = SubmitTask {
authenticator: authenticator.clone(),
token: authenticator.token(),
host_provider,
zenith,
client: reqwest::Client::new(),
Expand All @@ -47,7 +47,7 @@ async fn main() -> eyre::Result<()> {
let tx_poller = tx_poller::TxPoller::new(&config);
let (tx_receiver, tx_poller_jh) = tx_poller.spawn();

let bundle_poller = bundler::BundlePoller::new(&config, authenticator.clone());
let bundle_poller = bundler::BundlePoller::new(&config, authenticator.token());
let (bundle_receiver, bundle_poller_jh) = bundle_poller.spawn();

let authenticator_jh = authenticator.spawn();
Expand All @@ -65,8 +65,11 @@ async fn main() -> eyre::Result<()> {

let build_jh = sim.clone().spawn_simulator_task(constants, sim_items.clone(), submit_channel);

let port = config.builder_port;
let server = serve_builder_with_span(([0, 0, 0, 0], port), span);
let server = serve_builder(([0, 0, 0, 0], config.builder_port));

// We have finished initializing the builder, so we can drop the init span
// guard.
drop(init_span_guard);

select! {
_ = tx_poller_jh => {
Expand Down
70 changes: 13 additions & 57 deletions src/service.rs
Original file line number Diff line number Diff line change
@@ -1,48 +1,10 @@
use std::{fmt::Debug, net::SocketAddr};

use axum::{
Router,
http::StatusCode,
response::{IntoResponse, Response},
routing::get,
};
use tracing::{Instrument, Span};

/// App result
pub type AppResult<T, E = AppError> = Result<T, E>;

/// App error. This is a wrapper around eyre::Report that also includes an HTTP
/// status code. It implements [`IntoResponse`] so that it can be returned as an
/// error type from [`axum::handler::Handler`]s.
#[derive(Debug)]
pub struct AppError {
code: StatusCode,
eyre: eyre::Report,
}

impl AppError {
/// Instantiate a new error with the bad request status code.
pub fn bad_req<E: std::error::Error + Send + Sync + 'static>(e: E) -> Self {
Self { code: StatusCode::BAD_REQUEST, eyre: e.into() }
}

/// Instantiate a new error with the bad request status code and an error
/// string.
pub fn bad_req_str(e: &str) -> Self {
Self { code: StatusCode::BAD_REQUEST, eyre: eyre::eyre!(e.to_owned()) }
}

/// Instantiate a new error with the internal server error status code.
pub fn server_err<E: std::error::Error + Send + Sync + 'static>(e: E) -> Self {
Self { code: StatusCode::INTERNAL_SERVER_ERROR, eyre: e.into() }
}
}

impl IntoResponse for AppError {
fn into_response(self) -> Response {
(self.code, format!("{}", self.eyre)).into_response()
}
}
use std::net::SocketAddr;

/// Return a 404 Not Found response
pub async fn return_404() -> Response {
Expand All @@ -55,26 +17,20 @@ pub async fn return_200() -> Response {
}

/// Serve a builder service on the given socket address.
pub fn serve_builder_with_span(
socket: impl Into<SocketAddr>,
span: Span,
) -> tokio::task::JoinHandle<()> {
pub fn serve_builder(socket: impl Into<SocketAddr>) -> tokio::task::JoinHandle<()> {
let router = Router::new().route("/healthcheck", get(return_200)).fallback(return_404);

let addr = socket.into();
tokio::spawn(
async move {
match tokio::net::TcpListener::bind(&addr).await {
Ok(listener) => {
if let Err(err) = axum::serve(listener, router).await {
tracing::error!(%err, "serve failed");
}
}
Err(err) => {
tracing::error!(%err, "failed to bind to the address");
tokio::spawn(async move {
match tokio::net::TcpListener::bind(&addr).await {
Ok(listener) => {
if let Err(err) = axum::serve(listener, router).await {
tracing::error!(%err, "serve failed");
}
};
}
.instrument(span),
)
}
Err(err) => {
tracing::error!(%err, "failed to bind to the address");
}
};
})
}
5 changes: 3 additions & 2 deletions src/tasks/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ use alloy::{
};
use chrono::{DateTime, Utc};
use eyre::Report;
use init4_bin_base::utils::calc::SlotCalculator;
use signet_sim::{BlockBuild, BuiltBlock, SimCache};
use signet_types::{SlotCalculator, config::SignetSystemConstants};
use signet_types::config::SignetSystemConstants;
use std::{
sync::{
Arc,
Expand Down Expand Up @@ -210,7 +211,7 @@ impl Simulator {
}
}

/// Spawns the simulator task, which handles the setup and sets the deadline
/// Spawns the simulator task, which handles the setup and sets the deadline
/// for the each round of simulation.
///
/// # Arguments
Expand Down
30 changes: 15 additions & 15 deletions src/tasks/bundler.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
//! Bundler service responsible for fetching bundles and sending them to the simulator.
pub use crate::config::BuilderConfig;
use crate::tasks::oauth::Authenticator;
use crate::tasks::oauth::SharedToken;
use oauth2::TokenResponse;
use reqwest::{Client, Url};
use serde::{Deserialize, Serialize};
use signet_bundle::SignetEthBundle;
use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender, unbounded_channel};
use tokio::task::JoinHandle;
use tokio::time;
use tracing::{Instrument, debug, trace};
use tracing::{Instrument, debug, trace, warn};

pub use crate::config::BuilderConfig;

/// Holds a bundle from the cache with a unique ID and a Zenith bundle.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Bundle {
Expand All @@ -26,12 +28,12 @@ pub struct TxPoolBundleResponse {
}

/// The BundlePoller polls the tx-pool for bundles.
#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct BundlePoller {
/// The builder configuration values.
pub config: BuilderConfig,
/// Authentication module that periodically fetches and stores auth tokens.
pub authenticator: Authenticator,
pub token: SharedToken,
/// Holds a Reqwest client
pub client: Client,
/// Defines the interval at which the bundler polls the tx-pool for bundles.
Expand All @@ -41,28 +43,26 @@ pub struct BundlePoller {
/// Implements a poller for the block builder to pull bundles from the tx-pool.
impl BundlePoller {
/// Creates a new BundlePoller from the provided builder config.
pub fn new(config: &BuilderConfig, authenticator: Authenticator) -> Self {
Self {
config: config.clone(),
authenticator,
client: Client::new(),
poll_interval_ms: 1000,
}
pub fn new(config: &BuilderConfig, token: SharedToken) -> Self {
Self { config: config.clone(), token, client: Client::new(), poll_interval_ms: 1000 }
}

/// Creates a new BundlePoller from the provided builder config and with the specified poll interval in ms.
pub fn new_with_poll_interval_ms(
config: &BuilderConfig,
authenticator: Authenticator,
token: SharedToken,
poll_interval_ms: u64,
) -> Self {
Self { config: config.clone(), authenticator, client: Client::new(), poll_interval_ms }
Self { config: config.clone(), token, client: Client::new(), poll_interval_ms }
}

/// Fetches bundles from the transaction cache and returns them.
pub async fn check_bundle_cache(&mut self) -> eyre::Result<Vec<Bundle>> {
let bundle_url: Url = Url::parse(&self.config.tx_pool_url)?.join("bundles")?;
let token = self.authenticator.fetch_oauth_token().await?;
let Some(token) = self.token.read() else {
warn!("No token available, skipping bundle fetch");
return Ok(vec![]);
};

let result = self
.client
Expand Down
Loading