ethl-cli 0.1.31

Tools for capturing, processing, archiving, and replaying Ethereum events
Documentation
use anyhow::Result;
use clap::Parser;
use ethl::storage::merger::EventFileMerger;
use parse_size::parse_size;
use tracing::info;

use crate::commands::full_signatures_to_events;

fn value_parse_size(s: &str) -> Result<u64, String> {
    parse_size(s).map_err(|e| e.to_string())
}

#[derive(Parser, Debug)]
pub struct MergeArgs {
    /// Full event signatures to filter and parse against (e.g. "event Transfer(address from,address to,uint256 amount)")
    #[arg(long, required = true)]
    events: Vec<String>,

    /// The archived events location (eg: file:///tmp/events or s3://my-bucket/events)
    #[arg(long, required = true)]
    archive_path: String,

    /// Minimum file size in bytes to trigger a new file (default: 50MB)
    /// Note: this is a soft limit, files may be larger if a single batch of logs exceeds this size
    #[arg(long, value_parser = value_parse_size, help = "File size limit (e.g., '10MB', '2GiB')")]
    min_size: u64,

    /// Dry run - show what would be merged but do not perform any merges
    #[arg(long, default_value_t = false)]
    dry_run: bool,
}

pub async fn run_merge_command(args: MergeArgs) -> Result<()> {
    let events = full_signatures_to_events(&args.events)?;
    let archives = events
        .into_iter()
        .map(|e| {
            (
                e.clone(),
                EventFileMerger::new(&args.archive_path, args.min_size, e),
            )
        })
        .collect::<Vec<_>>();

    for (event, merger_res) in archives {
        let merger = merger_res?;
        let plan = merger.generate_plan().await?;

        if args.dry_run {
            info!("DRY RUN: Merge plan for event {}:\n{}", event.name, plan);
            continue;
        }
        merger.execute_plan(plan).await?;
    }

    Ok(())
}