Skip to content

Commit

Permalink
refactor(cli): merge argument parsing and command execution (#1568)
Browse files Browse the repository at this point in the history
## Summary
Refactors the CLI to give it a cleaner structure.

## Background
The CLI was split into a `cli` module that was concerned with parsing
arguments, and a `commands` which consumed the argument data structures.

The patch clears this up by implementing inherent `<Args>::run` methods
on all leaf argument types, so that the implementation follows the same
structure for all its effects.

Note that this match does restructure the public facing command line
(except for a few lines of documentation). It merely restructures the
implementation.

## Changes
- Refactors each type deriving `clap::Args` to have an inherent method
`run`.
- Flattens the crate structure to not be unnecessarily nested.

## Testing
These will be tested in follow PRs. Smoke tests using a subset of the
astria CLI commands should still work.

## Related Issues
Closes #1546
  • Loading branch information
SuperFluffy authored Oct 2, 2024
1 parent 939a689 commit 29a5d19
Show file tree
Hide file tree
Showing 23 changed files with 1,233 additions and 634 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
use std::{
collections::BTreeMap,
path::{
Path,
PathBuf,
},
path::PathBuf,
sync::Arc,
time::Duration,
};
Expand All @@ -12,20 +8,15 @@ use astria_bridge_contracts::{
GetWithdrawalActions,
GetWithdrawalActionsBuilder,
};
use astria_core::{
primitive::v1::{
asset::{
self,
},
Address,
use astria_core::primitive::v1::{
asset::{
self,
},
protocol::transaction::v1alpha1::Action,
Address,
};
use clap::Args;
use color_eyre::eyre::{
self,
bail,
ensure,
eyre,
OptionExt as _,
WrapErr as _,
Expand All @@ -49,8 +40,10 @@ use tracing::{
warn,
};

#[derive(Args, Debug)]
pub(crate) struct WithdrawalEvents {
use super::ActionsByRollupHeight;

#[derive(clap::Args, Debug)]
pub(super) struct Command {
/// The websocket endpoint of a geth compatible rollup.
#[arg(long)]
rollup_endpoint: String,
Expand Down Expand Up @@ -88,8 +81,8 @@ pub(crate) struct WithdrawalEvents {
force: bool,
}

impl WithdrawalEvents {
pub(crate) async fn run(self) -> eyre::Result<()> {
impl Command {
pub(super) async fn run(self) -> eyre::Result<()> {
let Self {
rollup_endpoint,
contract_address,
Expand All @@ -103,7 +96,8 @@ impl WithdrawalEvents {
force,
} = self;

let output = open_output(&output, force).wrap_err("failed to open output for writing")?;
let output =
super::open_output(&output, force).wrap_err("failed to open output for writing")?;

let block_provider = connect_to_rollup(&rollup_endpoint)
.await
Expand Down Expand Up @@ -209,36 +203,6 @@ async fn block_to_actions(
actions_by_rollup_height.insert(rollup_height, actions)
}

#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(transparent)]
pub(crate) struct ActionsByRollupHeight(BTreeMap<u64, Vec<Action>>);

impl ActionsByRollupHeight {
fn new() -> Self {
Self(BTreeMap::new())
}

pub(crate) fn into_inner(self) -> BTreeMap<u64, Vec<Action>> {
self.0
}

#[instrument(skip_all, err)]
fn insert(&mut self, rollup_height: u64, actions: Vec<Action>) -> eyre::Result<()> {
ensure!(
self.0.insert(rollup_height, actions).is_none(),
"already collected actions for block at rollup height `{rollup_height}`; no 2 blocks \
with the same height should have been seen",
);
Ok(())
}

#[instrument(skip_all, fields(target = %output.path.display()), err)]
fn write_to_output(self, output: Output) -> eyre::Result<()> {
let writer = std::io::BufWriter::new(output.handle);
serde_json::to_writer(writer, &self.0).wrap_err("failed writing actions to file")
}
}

/// Constructs a block stream from `start` until `maybe_end`, if `Some`.
/// Constructs an open ended stream from `start` if `None`.
#[instrument(skip_all, fields(start, end = maybe_end), err)]
Expand Down Expand Up @@ -292,31 +256,6 @@ async fn create_stream_of_blocks(
Ok(subscription)
}

#[derive(Debug)]
struct Output {
handle: std::fs::File,
path: PathBuf,
}

#[instrument(skip(target), fields(target = %target.as_ref().display()), err)]
fn open_output<P: AsRef<Path>>(target: P, overwrite: bool) -> eyre::Result<Output> {
let handle = if overwrite {
let mut options = std::fs::File::options();
options.write(true).create(true).truncate(true);
options
} else {
let mut options = std::fs::File::options();
options.write(true).create_new(true);
options
}
.open(&target)
.wrap_err("failed to open specified file for writing")?;
Ok(Output {
handle,
path: target.as_ref().to_path_buf(),
})
}

#[instrument(err)]
async fn connect_to_rollup(rollup_endpoint: &str) -> eyre::Result<Arc<Provider<Ws>>> {
let retry_config = tryhard::RetryFutureConfig::new(10)
Expand Down
97 changes: 97 additions & 0 deletions crates/astria-cli/src/bridge/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
mod collect;
mod submit;

use std::{
collections::BTreeMap,
path::{
Path,
PathBuf,
},
};

use astria_core::protocol::transaction::v1alpha1::Action;
use clap::Subcommand;
use color_eyre::eyre::{
self,
ensure,
WrapErr as _,
};
use tracing::instrument;

/// Interact with a Sequencer node
#[derive(Debug, clap::Args)]
pub(super) struct Command {
#[command(subcommand)]
command: SubCommand,
}

impl Command {
pub(super) async fn run(self) -> eyre::Result<()> {
match self.command {
SubCommand::CollectWithdrawals(args) => args.run().await,
SubCommand::SubmitWithdrawals(args) => args.run().await,
}
}
}

#[derive(Debug, Subcommand)]
enum SubCommand {
/// Commands for interacting with Sequencer accounts
CollectWithdrawals(collect::Command),
SubmitWithdrawals(submit::Command),
}

#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(transparent)]
struct ActionsByRollupHeight(BTreeMap<u64, Vec<Action>>);

impl ActionsByRollupHeight {
fn new() -> Self {
Self(BTreeMap::new())
}

fn into_inner(self) -> BTreeMap<u64, Vec<Action>> {
self.0
}

#[instrument(skip_all, err)]
fn insert(&mut self, rollup_height: u64, actions: Vec<Action>) -> eyre::Result<()> {
ensure!(
self.0.insert(rollup_height, actions).is_none(),
"already collected actions for block at rollup height `{rollup_height}`; no 2 blocks \
with the same height should have been seen",
);
Ok(())
}

#[instrument(skip_all, fields(target = %output.path.display()), err)]
fn write_to_output(self, output: Output) -> eyre::Result<()> {
let writer = std::io::BufWriter::new(output.handle);
serde_json::to_writer(writer, &self.0).wrap_err("failed writing actions to file")
}
}

#[derive(Debug)]
struct Output {
handle: std::fs::File,
path: PathBuf,
}

#[instrument(skip(target), fields(target = %target.as_ref().display()), err)]
fn open_output<P: AsRef<Path>>(target: P, overwrite: bool) -> eyre::Result<Output> {
let handle = if overwrite {
let mut options = std::fs::File::options();
options.write(true).create(true).truncate(true);
options
} else {
let mut options = std::fs::File::options();
options.write(true).create_new(true);
options
}
.open(&target)
.wrap_err("failed to open specified file for writing")?;
Ok(Output {
handle,
path: target.as_ref().to_path_buf(),
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use astria_sequencer_client::{
HttpClient,
SequencerClientExt as _,
};
use clap::Args;
use color_eyre::eyre::{
self,
ensure,
Expand All @@ -29,8 +28,8 @@ use tracing::{
warn,
};

#[derive(Args, Debug)]
pub(crate) struct WithdrawalEvents {
#[derive(clap::Args, Debug)]
pub(crate) struct Command {
#[arg(long, short)]
input: PathBuf,
#[arg(long)]
Expand All @@ -43,7 +42,7 @@ pub(crate) struct WithdrawalEvents {
sequencer_url: String,
}

impl WithdrawalEvents {
impl Command {
pub(crate) async fn run(self) -> eyre::Result<()> {
let signing_key = read_signing_key(&self.signing_key).wrap_err_with(|| {
format!(
Expand Down Expand Up @@ -96,7 +95,7 @@ impl WithdrawalEvents {
}
}

fn read_actions<P: AsRef<Path>>(path: P) -> eyre::Result<super::collect::ActionsByRollupHeight> {
fn read_actions<P: AsRef<Path>>(path: P) -> eyre::Result<super::ActionsByRollupHeight> {
let s = std::fs::read_to_string(path).wrap_err("failed buffering file contents as string")?;
serde_json::from_str(&s)
.wrap_err("failed deserializing file contents height-to-sequencer-actions serde object")
Expand Down
46 changes: 0 additions & 46 deletions crates/astria-cli/src/cli/mod.rs

This file was deleted.

Loading

0 comments on commit 29a5d19

Please sign in to comment.