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: Add trait for extending the cli with custom inspectors #513

Closed
wants to merge 2 commits into from
Closed
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
29 changes: 29 additions & 0 deletions crates/bin/src/cli/ext.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use alloy_primitives::Address;
use brontes_inspect::DynMevInspector;
use brontes_types::db::{cex::CexExchange, traits::LibmdbxReader};
use clap::Args;

/// Implement this trait to extend brontes with your own [Inspector](s).
pub trait InspectorCliExt {
/// Override this to initialize your custom [Inspector](s).
fn init_mev_inspectors<DB: LibmdbxReader>(
&self,
quote_token: Address,
db: &'static DB,
cex_exchanges: &[CexExchange],
) -> Vec<DynMevInspector>;
}

/// Noop impl for [InspectorCliExt].
#[derive(Debug, Clone, Copy, Default, Args)]
pub struct NoopInspectorCliExt;
impl InspectorCliExt for NoopInspectorCliExt {
fn init_mev_inspectors<DB: LibmdbxReader>(
&self,
_quote_token: Address,
_db: &'static DB,
_cex_exchanges: &[CexExchange],
) -> Vec<DynMevInspector> {
vec![]
}
}
11 changes: 7 additions & 4 deletions crates/bin/src/cli/mod.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
use clap::{Parser, Subcommand};

use crate::cli::ext::{InspectorCliExt, NoopInspectorCliExt};

mod analytics;
mod db;
mod run;
mod utils;

pub use utils::*;
pub mod ext;

#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
#[command(name = "brontes", author = "Sorella Labs", version = "0.1.0")]
#[command(propagate_version = true)]
pub struct Args {
pub struct Args<Ext: InspectorCliExt + clap::Args = NoopInspectorCliExt> {
#[clap(subcommand)]
pub command: Commands,
pub command: Commands<Ext>,
}

#[derive(Debug, Subcommand)]
pub enum Commands {
pub enum Commands<Ext: InspectorCliExt + clap::Args> {
/// Run brontes
#[command(name = "run")]
Run(run::RunArgs),
Run(run::RunArgs<Ext>),
/// Brontes database commands
#[command(name = "db")]
Database(db::Database),
Expand Down
24 changes: 20 additions & 4 deletions crates/bin/src/cli/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,19 @@ use brontes_inspect::Inspectors;
use brontes_metrics::PoirotMetricsListener;
use brontes_types::{constants::USDT_ADDRESS_STRING, init_threadpools};
use clap::Parser;

use tokio::sync::mpsc::unbounded_channel;

use super::{determine_max_tasks, get_env_vars, load_clickhouse, load_database, static_object};
use crate::{
banner,
cli::{get_tracing_provider, init_inspectors},
cli::{ext::InspectorCliExt, get_tracing_provider, init_inspectors, parse_cex_exchanges},
runner::CliContext,
BrontesRunConfig, MevProcessor,
};

#[derive(Debug, Parser)]
pub struct RunArgs {
pub struct RunArgs<Ext: InspectorCliExt + clap::Args> {
/// Start Block
#[arg(long, short)]
pub start_block: u64,
Expand Down Expand Up @@ -46,9 +47,12 @@ pub struct RunArgs {
/// How many blocks behind chain tip to run.
#[arg(long, default_value = "2")]
pub behind_tip: u64,
/// Additional cli arguments
#[command(flatten, next_help_heading = "Extension")]
pub ext: Ext,
}

impl RunArgs {
impl<Ext: InspectorCliExt + clap::Args> RunArgs<Ext> {
pub async fn execute(self, ctx: CliContext) -> eyre::Result<()> {
banner::print_banner();
// Fetch required environment variables.
Expand All @@ -73,7 +77,19 @@ impl RunArgs {
let clickhouse = static_object(load_clickhouse().await?);
tracing::info!(target: "brontes", "databases initialized");

let inspectors = init_inspectors(quote_asset, libmdbx, self.inspectors, self.cex_exchanges);
let inspectors = {
let cex_exchanges = parse_cex_exchanges(self.cex_exchanges);
let inspectors: Vec<_> =
init_inspectors(quote_asset, libmdbx, self.inspectors, &cex_exchanges)
.into_iter()
.chain(
self.ext
.init_mev_inspectors(quote_asset, libmdbx, &cex_exchanges),
)
.collect();
&*Box::leak(inspectors.into_boxed_slice())
};
tracing::info!(target: "brontes", "inspectors successfully initialized");

let tracer = get_tracing_provider(Path::new(&db_path), max_tasks, task_executor.clone());

Expand Down
22 changes: 12 additions & 10 deletions crates/bin/src/cli/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,27 +79,29 @@ pub fn static_object<T>(obj: T) -> &'static T {
&*Box::leak(Box::new(obj))
}

pub fn init_inspectors<DB: LibmdbxReader>(
quote_token: Address,
db: &'static DB,
inspectors: Option<Vec<Inspectors>>,
cex_exchanges: Option<Vec<String>>,
) -> &'static [&'static dyn Inspector<Result = Vec<Bundle>>] {
let cex_exchanges: Vec<CexExchange> = cex_exchanges
pub fn parse_cex_exchanges(cex_exchanges: Option<Vec<String>>) -> Vec<CexExchange> {
cex_exchanges
.unwrap_or_default()
.into_iter()
.map(|s| s.into())
.collect();
.collect()
}

pub fn init_inspectors<DB: LibmdbxReader>(
quote_token: Address,
db: &'static DB,
inspectors: Option<Vec<Inspectors>>,
cex_exchanges: &[CexExchange],
) -> Vec<&'static dyn Inspector<Result = Vec<Bundle>>> {
let mut res = Vec::new();
for inspector in inspectors
.map(|i| i.into_iter())
.unwrap_or_else(|| Inspectors::iter().collect_vec().into_iter())
{
res.push(inspector.init_mev_inspector(quote_token, db, &cex_exchanges));
res.push(inspector.init_mev_inspector(quote_token, db, cex_exchanges));
}

&*Box::leak(res.into_boxed_slice())
res
}

pub fn get_env_vars() -> eyre::Result<String> {
Expand Down
11 changes: 7 additions & 4 deletions crates/bin/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use std::error::Error;

use brontes::{
cli::{Args, Commands},
cli::{
ext::{InspectorCliExt, NoopInspectorCliExt},
Args, Commands,
},
runner,
};
use clap::Parser;
Expand All @@ -14,7 +17,7 @@ fn main() -> eyre::Result<()> {
init_tracing();
fdlimit::raise_fd_limit().unwrap();

match run() {
match run::<NoopInspectorCliExt>() {
Ok(()) => {
info!(target: "brontes", "successful shutdown");
Ok(())
Expand All @@ -32,8 +35,8 @@ fn main() -> eyre::Result<()> {
}
}

fn run() -> eyre::Result<()> {
let opt = Args::parse();
fn run<Ext: InspectorCliExt + clap::Args>() -> eyre::Result<()> {
Copy link
Author

@emostov emostov Mar 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can avoid all the extra + clap::Args by making InspectorCliExt a super trait of clap::Args - I don't feel strongly either way

let opt = Args::<Ext>::parse();
match opt.command {
Commands::Run(command) => runner::run_command_until_exit(|ctx| command.execute(ctx)),
Commands::Database(command) => runner::run_command_until_exit(|ctx| command.execute(ctx)),
Expand Down
7 changes: 4 additions & 3 deletions crates/brontes-inspect/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
//! }
//! ```
//!
//! The `Composer` uses to define a filter that
//! The `Composer` uses to define a filter that
//! orders results from individual inspectors. This ensures that lower-level
//! actions are composed before higher-level actions, which could affect the
//! composition.
Expand Down Expand Up @@ -108,6 +108,9 @@ use jit::JitInspector;
use liquidations::LiquidationInspector;
use sandwich::SandwichInspector;

pub type DynMevInspector = &'static (dyn Inspector<Result = Vec<Bundle>> + 'static);

/// Refer to crate level docs for information.
pub trait Inspector: Send + Sync {
type Result: Send + Sync;

Expand All @@ -129,8 +132,6 @@ pub enum Inspectors {
CexDexMarkout,
}

type DynMevInspector = &'static (dyn Inspector<Result = Vec<Bundle>> + 'static);

impl Inspectors {
pub fn init_mev_inspector<DB: LibmdbxReader>(
&self,
Expand Down