Skip to content
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
1,248 changes: 1,202 additions & 46 deletions Cargo.lock

Large diffs are not rendered by default.

39 changes: 36 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,45 @@ name = "kermit"
version = "0.1.0"
edition = "2021"

[lints.rust]
missing-debug-implementations = "warn"
unused-must-use = "deny"
unnameable-types = "warn"

[lints.clippy]
all = { level = "warn", priority = -1 }
explicit-into-iter-loop = "warn"
if-not-else = "warn"
ignored-unit-patterns = "warn"
inconsistent-struct-constructor = "warn"
large-enum-variant = "allow"
match-bool = "warn"
missing-const-for-fn = "warn"
missing-fields-in-debug = "warn"
needless-for-each = "warn"
needless-pass-by-value = "warn"
needless-raw-string-hashes = "warn"
non-std-lazy-statics = "warn"
option-if-let-else = "warn"
redundant-clone = "warn"
redundant-closure-for-method-calls = "warn"
ref-option = "warn"
semicolon-if-nothing-returned = "warn"
single-char-pattern = "warn"
uninlined-format-args = "warn"
unnecessary-semicolon = "warn"
unnecessary-wraps = "warn"
unused-self = "warn"
use-self = "warn"

[dependencies]
anyhow = "1.0.99"
anyhow = "1.0.100"
bigdecimal = "0.4.8"
clap = { version = "4", features = ["derive", "env"] }
regex = "1.11.2"
reqwest = { version = "0.12.23", features = ["json"] }
serde = {version = "1.0.219", features = ["derive"] }
serde_json = "1.0.143"
serde = {version = "1.0.226", features = ["derive"] }
serde_json = "1.0.145"
strum = { version = "0.26.3", features = ["derive"] }
hex = "0.4.3"
secp256k1 = "0.30.0"
Expand All @@ -18,3 +50,4 @@ tokio = { version = "1.47.1", features = ["full"] }
[dev-dependencies]
insta = { version = "1", features = ["filters"] }
insta-cmd = "0.6.0"
testcontainers = "0.25.0"
39 changes: 0 additions & 39 deletions src/address.rs

This file was deleted.

55 changes: 55 additions & 0 deletions src/addresses.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use anyhow::Result;
use clap::Parser;

use crate::common::{get, print_output};

/// CLI arguments for `kermit addresses`.
#[derive(Parser)]
pub(crate) enum AddressesSubcommands {
/// Get the balance of an address.
#[command(visible_alias = "b")]
Balance {
address: String,
#[arg(short, long, default_value_t = false)]
mem_pool: bool,
},

/// Get the UTXOs of an address.
#[command(visible_alias = "u")]
Utxos {
address: String,
#[arg(short, long, default_value_t = false)]
error_if_exceed_max_utxos: bool,
},

/// Get the group of an address.
#[command(visible_alias = "g")]
Group { address: String },
}

impl AddressesSubcommands {
pub(crate) async fn run(self, url: String) -> Result<()> {
let endpoint = match self {
Self::Balance { address, mem_pool } => {
format!("/addresses/{address}/balance?mempool={mem_pool}")
},
Self::Utxos {
address,
error_if_exceed_max_utxos,
} => {
format!(
"/addresses/{address}/utxos?\
error_if_exceed_max_utxos={error_if_exceed_max_utxos}"
)
},
Self::Group { address } => {
format!("/addresses/{address}/group")
},
};

let output = get(&url, &endpoint).await?;
print_output(output)?;

Ok(())
}
}
59 changes: 37 additions & 22 deletions src/args.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use clap::{Parser, Subcommand, ValueHint};

use crate::{
address::AddressSubcommands, contracts::ContractsSubcommands, events::EventsSubcommands,
infos::InfosSubcommands, transactions::TransactionsSubcommands, wallet::WalletsSubcommands,
addresses::AddressesSubcommands, blockflow::BlockflowSubcommands,
contracts::ContractsSubcommands, infos::InfosSubcommands, miners::MinersSubcommands,
transactions::TransactionsSubcommands, utils::UtilsSubcommands, wallets::WalletsSubcommands,
};

#[derive(Parser)]
#[command(version)]
pub struct Kermit {
pub(crate) struct Kermit {
#[clap(long, short, env, value_hint = ValueHint::Url,
default_value = "http://localhost:22973")]
pub url: String,
Expand All @@ -17,12 +18,26 @@ pub struct Kermit {
}

#[derive(Subcommand)]
pub enum KermitSubcommand {
/// Event for contract, block and hash.
#[command(visible_alias = "e")]
Events {
pub(crate) enum KermitSubcommand {
/// Address management utilities.
#[command(visible_alias = "a")]
Addresses {
#[command(subcommand)]
command: AddressesSubcommands,
},

/// Blockflow data retrieval utilities.
#[command(visible_alias = "b")]
Blockflow {
#[command(subcommand)]
command: EventsSubcommands,
command: BlockflowSubcommands,
},

/// Contract management utilities.
#[command(visible_alias = "c")]
Contracts {
#[command(subcommand)]
command: ContractsSubcommands,
},

/// Infos about node and hashrate.
Expand All @@ -32,6 +47,20 @@ pub enum KermitSubcommand {
command: InfosSubcommands,
},

/// Miners management utilities.
#[command(visible_alias = "m")]
Miners {
#[command(subcommand)]
command: MinersSubcommands,
},

/// Utilities (Address zero, Hash zero, Conversion atto).
#[command(visible_alias = "u")]
Utils {
#[command(subcommand)]
command: UtilsSubcommands,
},

/// Transactions management utilities
#[command(visible_alias = "tx")]
Transactions {
Expand All @@ -45,18 +74,4 @@ pub enum KermitSubcommand {
#[command(subcommand)]
command: WalletsSubcommands,
},

/// Address management utilities.
#[command(visible_alias = "a")]
Address {
#[command(subcommand)]
command: AddressSubcommands,
},

/// Contract management utilities.
#[command(visible_alias = "c")]
Contracts {
#[command(subcommand)]
command: ContractsSubcommands,
},
}
134 changes: 134 additions & 0 deletions src/blockflow.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
use anyhow::Result;
use clap::Parser;

use crate::common::{get, print_output};

/// CLI arguments for `kermit blockflow`.
#[derive(Parser)]
pub(crate) enum BlockflowSubcommands {
/// List blocks on the given time interval.
#[command(visible_alias = "bs")]
Blocks { from_ts: i64, to_ts: Option<i64> },

/// List blocks with events on the given time interval.
#[command(visible_alias = "bswe")]
BlocksWithEvents { from_ts: i64, to_ts: Option<i64> },

/// Given a time interval, list blocks containing events and transactions
/// with enriched input information when node indexes are enabled.
#[command(visible_alias = "rbs")]
RichBlocks { from_ts: i64, to_ts: Option<i64> },

/// Get a block with hash?
#[command(visible_alias = "b")]
Block { block_hash: String },

/// Get a mainchain block by ghost uncle hash.
#[command(visible_alias = "mcbbgu")]
MainChainBlockByGhostUncle { ghost_uncle_hash: String },

/// Get a block and events with hash.
#[command(visible_alias = "bwe")]
BlockWithEvents { block_hash: String },

/// Get a block containing events and transactions with enriched input
/// information when node indexes are enabled.
#[command(visible_alias = "rb")]
RichBlock { block_hash: String },

/// Check if the block is in main chain.
#[command(visible_alias = "ibimc")]
IsBlockInMainChain { block_hash: String },

/// Get all block's hashes at given height for given groups.
#[command(visible_alias = "hs")]
Hashes {
from_group: i64,
to_group: i64,
height: i64,
},

/// Get infos about the chain from the given groups.
#[command(visible_alias = "ci")]
ChainInfo { from_group: i64, to_group: i64 },

/// Get infos about the chain from the given groups.
#[command(visible_alias = "h")]
Header { block_hash: String },

/// Get raw block in hex format.
#[command(visible_alias = "rawb")]
RawBlock { block_hash: String },
}

impl BlockflowSubcommands {
pub(crate) async fn run(self, url: &str) -> Result<()> {
let endpoint = match self {
Self::Blocks { from_ts, to_ts } => {
let mut endpoint = format!("/blockflow/blocks?fromTs={from_ts}");
if let Some(to_ts) = to_ts {
endpoint.push_str(&format!("&toTs={to_ts}"));
}

endpoint
},
Self::BlocksWithEvents { from_ts, to_ts } => {
let mut endpoint = format!("/blockflow/blocks-with-events?fromTs={from_ts}");
if let Some(to_ts) = to_ts {
endpoint.push_str(&format!("&toTs={to_ts}"));
}

endpoint
},
Self::RichBlocks { from_ts, to_ts } => {
let mut endpoint = format!("/blockflow/rich-blocks?fromTs={from_ts}");
if let Some(to_ts) = to_ts {
endpoint.push_str(&format!("&toTs={to_ts}"));
}

endpoint
},
Self::Block { block_hash } => {
format!("/blockflow/blocks/{block_hash}")
},
Self::MainChainBlockByGhostUncle { ghost_uncle_hash } => {
format!("/blockflow/main-chain-block-by-ghost-uncle/{ghost_uncle_hash}")
},
Self::BlockWithEvents { block_hash } => {
format!("/blockflow/blocks-with-events/{block_hash}")
},
Self::RichBlock { block_hash } => {
format!("/blockflow/rich-blocks/{block_hash}")
},
Self::IsBlockInMainChain { block_hash } => {
format!("/blockflow/is-block-in-main-chain?blockHash={block_hash}")
},
Self::Hashes {
from_group,
to_group,
height,
} => {
format!(
"/blockflow/hashes?fromGroup={from_group}&toGroup={to_group}&height={height}",
)
},
Self::ChainInfo {
from_group,
to_group,
} => {
format!("/blockflow/chain-info?fromGroup={from_group}&toGroup={to_group}")
},
Self::Header { block_hash } => {
format!("/blockflow/headers/{block_hash}")
},
Self::RawBlock { block_hash } => {
format!("/blockflow/raw-blocks/{block_hash}")
},
};

let output = get(url, &endpoint).await?;
print_output(output)?;

Ok(())
}
}
5 changes: 5 additions & 0 deletions src/common/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mod reqwest;
pub(crate) use reqwest::*;

mod print;
pub(crate) use print::*;
2 changes: 1 addition & 1 deletion src/utils/print.rs → src/common/print.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use anyhow::Result;
use serde_json::Value;

pub fn print_output(output: Option<Value>) -> Result<()> {
pub(crate) fn print_output(output: Option<Value>) -> Result<()> {
if let Some(output) = output {
serde_json::to_writer_pretty(std::io::stdout(), &output)?;
println!();
Expand Down
Loading
Loading