Skip to content

Commit 848e429

Browse files
committed
move stackslib::cli to stacks-inspect
1 parent 5934517 commit 848e429

File tree

9 files changed

+101
-77
lines changed

9 files changed

+101
-77
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

contrib/stacks-inspect/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ stackslib = { package = "stackslib", path = "../../stackslib", default-features
88
clarity = { path = "../../clarity", default-features = false }
99
libstackerdb = { path = "../../libstackerdb", default-features = false }
1010
stacks-common = { path = "../../stacks-common", default-features = false }
11+
regex = { version = "1", default-features = false }
1112
rusqlite = { workspace = true }
1213
serde_json = { workspace = true }
1314
slog = { workspace = true }

contrib/stacks-inspect/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,18 @@ cargo build -p stacks-inspect
1717
Basic usage:
1818
```bash
1919
# Show version
20-
./target/debug/stacks-inspect --version
20+
cargo run -p stacks-inspect -- --version
2121

2222
# Example: decode a bitcoin header from file
23-
./target/debug/stacks-inspect decode-bitcoin-header <HEIGHT> <PATH>
23+
cargo run -p stacks-inspect -- decode-bitcoin-header <HEIGHT> <PATH>
2424

2525
# Example: analyze anti-MEV behavior over a height range
26-
./target/debug/stacks-inspect analyze-sortition-mev <burn_db> <sort_db> <chainstate_db> <start> <end> [miner advantage ...]
26+
cargo run -p stacks-inspect -- analyze-sortition-mev <burn_db> <sort_db> <chainstate_db> <start> <end> [miner advantage ...]
2727
```
2828

2929
For detailed commands and flags, run:
3030
```bash
31-
./target/debug/stacks-inspect --help
31+
cargo run -p stacks-inspect -- --help
3232
```
3333

3434
Notes:

stackslib/src/cli.rs renamed to contrib/stacks-inspect/src/lib.rs

Lines changed: 77 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
// Copyright (C) 2013-2020 Blockstack PBC, a public benefit corporation
2-
// Copyright (C) 2020 Stacks Open Internet Foundation
1+
// Copyright (C) 2025 Stacks Open Internet Foundation
32
//
43
// This program is free software: you can redistribute it and/or modify
54
// it under the terms of the GNU General Public License as published by
@@ -14,41 +13,42 @@
1413
// You should have received a copy of the GNU General Public License
1514
// along with this program. If not, see <http://www.gnu.org/licenses/>.
1615

17-
//! Subcommands used by `stacks-inspect` binary
18-
1916
use std::path::PathBuf;
2017
use std::time::Instant;
2118
use std::{fs, process};
2219

2320
use clarity::types::chainstate::SortitionId;
24-
use clarity::util::hash::{to_hex, Sha512Trunc256Sum};
25-
use db::blocks::DummyEventDispatcher;
26-
use db::ChainstateTx;
21+
use clarity::util::hash::{Sha512Trunc256Sum, to_hex};
2722
use regex::Regex;
2823
use rusqlite::{Connection, OpenFlags};
2924
use stacks_common::types::chainstate::{BlockHeaderHash, StacksBlockId};
3025
use stacks_common::types::sqlite::NO_PARAMS;
3126
use stacks_common::util::hash::Hash160;
3227
use stacks_common::util::vrf::VRFProof;
33-
34-
use crate::burnchains::Burnchain;
35-
use crate::chainstate::burn::db::sortdb::{
36-
get_ancestor_sort_id, SortitionDB, SortitionHandleContext,
28+
use stacks_common::{debug, info, warn};
29+
use stackslib::burnchains::Burnchain;
30+
use stackslib::chainstate::burn::ConsensusHash;
31+
use stackslib::chainstate::burn::db::sortdb::{
32+
SortitionDB, SortitionHandleContext, get_ancestor_sort_id,
33+
};
34+
use stackslib::chainstate::coordinator::OnChainRewardSetProvider;
35+
use stackslib::chainstate::nakamoto::miner::{
36+
BlockMetadata, NakamotoBlockBuilder, NakamotoTenureInfo,
37+
};
38+
use stackslib::chainstate::nakamoto::{NakamotoBlock, NakamotoChainState};
39+
use stackslib::chainstate::stacks::db::blocks::DummyEventDispatcher;
40+
use stackslib::chainstate::stacks::db::{
41+
ChainstateTx, StacksBlockHeaderTypes, StacksChainState, StacksHeaderInfo,
3742
};
38-
use crate::chainstate::burn::ConsensusHash;
39-
use crate::chainstate::coordinator::OnChainRewardSetProvider;
40-
use crate::chainstate::nakamoto::miner::{BlockMetadata, NakamotoBlockBuilder, NakamotoTenureInfo};
41-
use crate::chainstate::nakamoto::{NakamotoBlock, NakamotoChainState};
42-
use crate::chainstate::stacks::db::{StacksBlockHeaderTypes, StacksChainState, StacksHeaderInfo};
43-
use crate::chainstate::stacks::miner::*;
44-
use crate::chainstate::stacks::{Error as ChainstateError, *};
45-
use crate::clarity_vm::clarity::ClarityInstance;
46-
use crate::clarity_vm::database::GetTenureStartId;
47-
use crate::config::{Config, ConfigFile, DEFAULT_MAINNET_CONFIG};
48-
use crate::core::*;
49-
use crate::cost_estimates::metrics::UnitMetric;
50-
use crate::cost_estimates::UnitEstimator;
51-
use crate::util_lib::db::IndexDBTx;
43+
use stackslib::chainstate::stacks::miner::*;
44+
use stackslib::chainstate::stacks::{Error as ChainstateError, *};
45+
use stackslib::clarity_vm::clarity::ClarityInstance;
46+
use stackslib::clarity_vm::database::GetTenureStartId;
47+
use stackslib::config::{Config, ConfigFile, DEFAULT_MAINNET_CONFIG};
48+
use stackslib::core::*;
49+
use stackslib::cost_estimates::UnitEstimator;
50+
use stackslib::cost_estimates::metrics::UnitMetric;
51+
use stackslib::util_lib::db::IndexDBTx;
5252

5353
/// Options common to many `stacks-inspect` subcommands
5454
/// Returned by `process_common_opts()`
@@ -141,34 +141,38 @@ pub fn command_replay_block(argv: &[String], conf: Option<&Config>) {
141141

142142
let query = match mode {
143143
Some("prefix") => format!(
144-
"SELECT index_block_hash FROM staging_blocks WHERE orphaned = 0 AND index_block_hash LIKE \"{}%\"",
145-
argv[3]
146-
),
144+
"SELECT index_block_hash FROM staging_blocks WHERE orphaned = 0 AND index_block_hash LIKE \"{}%\"",
145+
argv[3]
146+
),
147147
Some("first") => format!(
148-
"SELECT index_block_hash FROM staging_blocks WHERE orphaned = 0 ORDER BY height ASC LIMIT {}",
149-
argv[3]
150-
),
148+
"SELECT index_block_hash FROM staging_blocks WHERE orphaned = 0 ORDER BY height ASC LIMIT {}",
149+
argv[3]
150+
),
151151
Some("range") => {
152152
let arg4 = argv[3]
153153
.parse::<u64>()
154154
.expect("<start_block> not a valid u64");
155155
let arg5 = argv[4].parse::<u64>().expect("<end-block> not a valid u64");
156156
let start = arg4.saturating_sub(1);
157157
let blocks = arg5.saturating_sub(arg4);
158-
format!("SELECT index_block_hash FROM staging_blocks WHERE orphaned = 0 ORDER BY height ASC LIMIT {start}, {blocks}")
158+
format!(
159+
"SELECT index_block_hash FROM staging_blocks WHERE orphaned = 0 ORDER BY height ASC LIMIT {start}, {blocks}"
160+
)
159161
}
160162
Some("index-range") => {
161163
let start = argv[3]
162164
.parse::<u64>()
163165
.expect("<start_block> not a valid u64");
164166
let end = argv[4].parse::<u64>().expect("<end-block> not a valid u64");
165167
let blocks = end.saturating_sub(start);
166-
format!("SELECT index_block_hash FROM staging_blocks WHERE orphaned = 0 ORDER BY index_block_hash ASC LIMIT {start}, {blocks}")
168+
format!(
169+
"SELECT index_block_hash FROM staging_blocks WHERE orphaned = 0 ORDER BY index_block_hash ASC LIMIT {start}, {blocks}"
170+
)
167171
}
168172
Some("last") => format!(
169-
"SELECT index_block_hash FROM staging_blocks WHERE orphaned = 0 ORDER BY height DESC LIMIT {}",
170-
argv[3]
171-
),
173+
"SELECT index_block_hash FROM staging_blocks WHERE orphaned = 0 ORDER BY height DESC LIMIT {}",
174+
argv[3]
175+
),
172176
Some(_) => print_help_and_exit(),
173177
// Default to ALL blocks
174178
None => "SELECT index_block_hash FROM staging_blocks WHERE orphaned = 0".into(),
@@ -229,34 +233,38 @@ pub fn command_replay_block_nakamoto(argv: &[String], conf: Option<&Config>) {
229233

230234
let query = match mode {
231235
Some("prefix") => format!(
232-
"SELECT index_block_hash FROM nakamoto_staging_blocks WHERE orphaned = 0 AND index_block_hash LIKE \"{}%\"",
233-
argv[3]
234-
),
236+
"SELECT index_block_hash FROM nakamoto_staging_blocks WHERE orphaned = 0 AND index_block_hash LIKE \"{}%\"",
237+
argv[3]
238+
),
235239
Some("first") => format!(
236-
"SELECT index_block_hash FROM nakamoto_staging_blocks WHERE orphaned = 0 ORDER BY height ASC LIMIT {}",
237-
argv[3]
238-
),
240+
"SELECT index_block_hash FROM nakamoto_staging_blocks WHERE orphaned = 0 ORDER BY height ASC LIMIT {}",
241+
argv[3]
242+
),
239243
Some("range") => {
240244
let arg4 = argv[3]
241245
.parse::<u64>()
242246
.expect("<start_block> not a valid u64");
243247
let arg5 = argv[4].parse::<u64>().expect("<end-block> not a valid u64");
244248
let start = arg4.saturating_sub(1);
245249
let blocks = arg5.saturating_sub(arg4);
246-
format!("SELECT index_block_hash FROM nakamoto_staging_blocks WHERE orphaned = 0 ORDER BY height ASC LIMIT {start}, {blocks}")
250+
format!(
251+
"SELECT index_block_hash FROM nakamoto_staging_blocks WHERE orphaned = 0 ORDER BY height ASC LIMIT {start}, {blocks}"
252+
)
247253
}
248254
Some("index-range") => {
249255
let start = argv[3]
250256
.parse::<u64>()
251257
.expect("<start_block> not a valid u64");
252258
let end = argv[4].parse::<u64>().expect("<end-block> not a valid u64");
253259
let blocks = end.saturating_sub(start);
254-
format!("SELECT index_block_hash FROM nakamoto_staging_blocks WHERE orphaned = 0 ORDER BY index_block_hash ASC LIMIT {start}, {blocks}")
260+
format!(
261+
"SELECT index_block_hash FROM nakamoto_staging_blocks WHERE orphaned = 0 ORDER BY index_block_hash ASC LIMIT {start}, {blocks}"
262+
)
255263
}
256264
Some("last") => format!(
257-
"SELECT index_block_hash FROM nakamoto_staging_blocks WHERE orphaned = 0 ORDER BY height DESC LIMIT {}",
258-
argv[3]
259-
),
265+
"SELECT index_block_hash FROM nakamoto_staging_blocks WHERE orphaned = 0 ORDER BY height DESC LIMIT {}",
266+
argv[3]
267+
),
260268
Some(_) => print_help_and_exit(),
261269
// Default to ALL blocks
262270
None => "SELECT index_block_hash FROM nakamoto_staging_blocks WHERE orphaned = 0".into(),
@@ -386,8 +394,12 @@ pub fn command_try_mine(argv: &[String], conf: Option<&Config>) {
386394
let n = &argv[0];
387395
eprintln!("Usage: {n} <working-dir> [min-fee [max-time]]");
388396
eprintln!("");
389-
eprintln!("Given a <working-dir>, try to ''mine'' an anchored block. This invokes the miner block");
390-
eprintln!("assembly, but does not attempt to broadcast a block commit. This is useful for determining");
397+
eprintln!(
398+
"Given a <working-dir>, try to ''mine'' an anchored block. This invokes the miner block"
399+
);
400+
eprintln!(
401+
"assembly, but does not attempt to broadcast a block commit. This is useful for determining"
402+
);
391403
eprintln!("what transactions a given chain state would include in an anchor block,");
392404
eprintln!("or otherwise simulating a miner.");
393405
process::exit(1);
@@ -523,11 +535,11 @@ pub fn command_try_mine(argv: &[String], conf: Option<&Config>) {
523535
let elapsed = start.elapsed();
524536
let summary = format!(
525537
"block @ height = {h} off of {pid} ({pch}/{pbh}) in {t}ms. Min-fee: {min_fee}, Max-time: {max_time}",
526-
h=parent_stacks_header.stacks_block_height + 1,
527-
pid=&parent_stacks_header.index_block_hash(),
528-
pch=&parent_stacks_header.consensus_hash,
529-
pbh=&parent_stacks_header.anchored_header.block_hash(),
530-
t=elapsed.as_millis(),
538+
h = parent_stacks_header.stacks_block_height + 1,
539+
pid = &parent_stacks_header.index_block_hash(),
540+
pch = &parent_stacks_header.consensus_hash,
541+
pbh = &parent_stacks_header.anchored_header.block_hash(),
542+
t = elapsed.as_millis(),
531543
);
532544

533545
let code = match result {
@@ -770,7 +782,9 @@ fn replay_block(
770782
),
771783
None => {
772784
// shouldn't happen
773-
panic!("CORRUPTION: staging block {block_consensus_hash}/{block_hash} does not correspond to a burn block");
785+
panic!(
786+
"CORRUPTION: staging block {block_consensus_hash}/{block_hash} does not correspond to a burn block"
787+
);
774788
}
775789
};
776790

@@ -835,8 +849,10 @@ fn replay_block(
835849
) {
836850
Ok((receipt, _, _)) => {
837851
if receipt.anchored_block_cost != cost {
838-
println!("Failed processing block! block = {block_id}. Unexpected cost. expected = {cost}, evaluated = {}",
839-
receipt.anchored_block_cost);
852+
println!(
853+
"Failed processing block! block = {block_id}. Unexpected cost. expected = {cost}, evaluated = {}",
854+
receipt.anchored_block_cost
855+
);
840856
process::exit(1);
841857
}
842858

@@ -1153,7 +1169,9 @@ fn replay_block_nakamoto(
11531169
// check the cost
11541170
let evaluated_cost = receipt.anchored_block_cost.clone();
11551171
if evaluated_cost != expected_cost {
1156-
println!("Failed processing block! block = {block_id}. Unexpected cost. expected = {expected_cost}, evaluated = {evaluated_cost}");
1172+
println!(
1173+
"Failed processing block! block = {block_id}. Unexpected cost. expected = {expected_cost}, evaluated = {evaluated_cost}"
1174+
);
11571175
process::exit(1);
11581176
}
11591177
}
@@ -1197,7 +1215,7 @@ pub mod test {
11971215
"stacks-inspect try-mine --config my_config.toml /tmp/chainstate/mainnet",
11981216
);
11991217
let argv_init = argv.clone();
1200-
let opts = drain_common_opts(&mut argv, 0);
1218+
let _opts = drain_common_opts(&mut argv, 0);
12011219
let opts = drain_common_opts(&mut argv, 1);
12021220

12031221
assert_eq!(argv, argv_init);

contrib/stacks-inspect/src/main.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ extern crate stacks_common;
1919
use clarity::consts::CHAIN_ID_MAINNET;
2020
use clarity::types::StacksEpochId;
2121
use clarity::types::chainstate::StacksPrivateKey;
22+
use clarity_cli::DEFAULT_CLI_EPOCH;
23+
use stacks_inspect::{
24+
command_contract_hash, command_replay_block, command_replay_block_nakamoto,
25+
command_replay_mock_mining, command_try_mine, drain_common_opts,
26+
};
2227
use stackslib::chainstate::stacks::miner::BlockBuilderSettings;
2328
use stackslib::chainstate::stacks::{
2429
CoinbasePayload, StacksBlock, StacksBlockBuilder, StacksMicroblock, StacksTransaction,
@@ -80,6 +85,7 @@ use stackslib::chainstate::stacks::index::marf::{MARF, MARFOpenOpts, MarfConnect
8085
use stackslib::clarity::vm::ClarityVersion;
8186
use stackslib::clarity::vm::costs::ExecutionCost;
8287
use stackslib::clarity::vm::types::StacksAddressExtensions;
88+
use stackslib::clarity_cli;
8389
use stackslib::core::MemPoolDB;
8490
use stackslib::cost_estimates::UnitEstimator;
8591
use stackslib::cost_estimates::metrics::UnitMetric;
@@ -91,7 +97,6 @@ use stackslib::net::relay::Relayer;
9197
use stackslib::net::{GetNakamotoInvData, HandshakeData, StacksMessage, StacksMessageType};
9298
use stackslib::util_lib::db::sqlite_open;
9399
use stackslib::util_lib::strings::UrlString;
94-
use stackslib::{clarity_cli, cli};
95100

96101
struct P2PSession {
97102
pub local_peer: LocalPeer,
@@ -301,7 +306,7 @@ fn main() {
301306
process::exit(1);
302307
}
303308

304-
let common_opts = cli::drain_common_opts(&mut argv, 1);
309+
let common_opts = drain_common_opts(&mut argv, 1);
305310

306311
if argv[1] == "--version" {
307312
println!(
@@ -789,7 +794,7 @@ check if the associated microblocks can be downloaded
789794
}
790795

791796
if argv[1] == "try-mine" {
792-
cli::command_try_mine(&argv[1..], common_opts.config.as_ref());
797+
command_try_mine(&argv[1..], common_opts.config.as_ref());
793798
process::exit(0);
794799
}
795800

@@ -896,7 +901,7 @@ check if the associated microblocks can be downloaded
896901
}
897902
let program: String = fs::read_to_string(&argv[2])
898903
.unwrap_or_else(|_| panic!("Error reading file: {}", argv[2]));
899-
let clarity_version = ClarityVersion::default_for_epoch(clarity_cli::DEFAULT_CLI_EPOCH);
904+
let clarity_version = ClarityVersion::default_for_epoch(DEFAULT_CLI_EPOCH);
900905
match clarity_cli::vm_execute(&program, clarity_version) {
901906
Ok(Some(result)) => println!("{result}"),
902907
Ok(None) => println!(),
@@ -1582,17 +1587,17 @@ check if the associated microblocks can be downloaded
15821587
}
15831588

15841589
if argv[1] == "replay-block" {
1585-
cli::command_replay_block(&argv[1..], common_opts.config.as_ref());
1590+
command_replay_block(&argv[1..], common_opts.config.as_ref());
15861591
process::exit(0);
15871592
}
15881593

15891594
if argv[1] == "replay-naka-block" {
1590-
cli::command_replay_block_nakamoto(&argv[1..], common_opts.config.as_ref());
1595+
command_replay_block_nakamoto(&argv[1..], common_opts.config.as_ref());
15911596
process::exit(0);
15921597
}
15931598

15941599
if argv[1] == "replay-mock-mining" {
1595-
cli::command_replay_mock_mining(&argv[1..], common_opts.config.as_ref());
1600+
command_replay_mock_mining(&argv[1..], common_opts.config.as_ref());
15961601
process::exit(0);
15971602
}
15981603

@@ -1601,7 +1606,7 @@ check if the associated microblocks can be downloaded
16011606
}
16021607

16031608
if argv[1] == "contract-hash" {
1604-
cli::command_contract_hash(&argv[1..], common_opts.config.as_ref());
1609+
command_contract_hash(&argv[1..], common_opts.config.as_ref());
16051610
process::exit(0);
16061611
}
16071612

stacks-node/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ clarity = { path = "../clarity", features = ["default", "testing"]}
4848
stacks-common = { path = "../stacks-common", features = ["default", "testing"] }
4949
stacks = { package = "stackslib", path = "../stackslib", features = ["default", "testing"] }
5050
stacks-signer = { path = "../stacks-signer", features = ["testing"] }
51+
stacks-inspect = { path = "../contrib/stacks-inspect", default-features = false }
5152
tracing = "0.1.37"
5253
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
5354
mutants = "0.0.3"

0 commit comments

Comments
 (0)