|
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 |
3 | 2 | //
|
4 | 3 | // This program is free software: you can redistribute it and/or modify
|
5 | 4 | // it under the terms of the GNU General Public License as published by
|
|
14 | 13 | // You should have received a copy of the GNU General Public License
|
15 | 14 | // along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16 | 15 |
|
17 |
| -//! Subcommands used by `stacks-inspect` binary |
18 |
| -
|
19 | 16 | use std::path::PathBuf;
|
20 | 17 | use std::time::Instant;
|
21 | 18 | use std::{fs, process};
|
22 | 19 |
|
23 | 20 | 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}; |
27 | 22 | use regex::Regex;
|
28 | 23 | use rusqlite::{Connection, OpenFlags};
|
29 | 24 | use stacks_common::types::chainstate::{BlockHeaderHash, StacksBlockId};
|
30 | 25 | use stacks_common::types::sqlite::NO_PARAMS;
|
31 | 26 | use stacks_common::util::hash::Hash160;
|
32 | 27 | 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, |
37 | 42 | };
|
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; |
52 | 52 |
|
53 | 53 | /// Options common to many `stacks-inspect` subcommands
|
54 | 54 | /// Returned by `process_common_opts()`
|
@@ -141,34 +141,38 @@ pub fn command_replay_block(argv: &[String], conf: Option<&Config>) {
|
141 | 141 |
|
142 | 142 | let query = match mode {
|
143 | 143 | 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 | + ), |
147 | 147 | 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 | + ), |
151 | 151 | Some("range") => {
|
152 | 152 | let arg4 = argv[3]
|
153 | 153 | .parse::<u64>()
|
154 | 154 | .expect("<start_block> not a valid u64");
|
155 | 155 | let arg5 = argv[4].parse::<u64>().expect("<end-block> not a valid u64");
|
156 | 156 | let start = arg4.saturating_sub(1);
|
157 | 157 | 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 | + ) |
159 | 161 | }
|
160 | 162 | Some("index-range") => {
|
161 | 163 | let start = argv[3]
|
162 | 164 | .parse::<u64>()
|
163 | 165 | .expect("<start_block> not a valid u64");
|
164 | 166 | let end = argv[4].parse::<u64>().expect("<end-block> not a valid u64");
|
165 | 167 | 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 | + ) |
167 | 171 | }
|
168 | 172 | 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 | + ), |
172 | 176 | Some(_) => print_help_and_exit(),
|
173 | 177 | // Default to ALL blocks
|
174 | 178 | 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>) {
|
229 | 233 |
|
230 | 234 | let query = match mode {
|
231 | 235 | 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 | + ), |
235 | 239 | 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 | + ), |
239 | 243 | Some("range") => {
|
240 | 244 | let arg4 = argv[3]
|
241 | 245 | .parse::<u64>()
|
242 | 246 | .expect("<start_block> not a valid u64");
|
243 | 247 | let arg5 = argv[4].parse::<u64>().expect("<end-block> not a valid u64");
|
244 | 248 | let start = arg4.saturating_sub(1);
|
245 | 249 | 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 | + ) |
247 | 253 | }
|
248 | 254 | Some("index-range") => {
|
249 | 255 | let start = argv[3]
|
250 | 256 | .parse::<u64>()
|
251 | 257 | .expect("<start_block> not a valid u64");
|
252 | 258 | let end = argv[4].parse::<u64>().expect("<end-block> not a valid u64");
|
253 | 259 | 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 | + ) |
255 | 263 | }
|
256 | 264 | 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 | + ), |
260 | 268 | Some(_) => print_help_and_exit(),
|
261 | 269 | // Default to ALL blocks
|
262 | 270 | 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>) {
|
386 | 394 | let n = &argv[0];
|
387 | 395 | eprintln!("Usage: {n} <working-dir> [min-fee [max-time]]");
|
388 | 396 | 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 | + ); |
391 | 403 | eprintln!("what transactions a given chain state would include in an anchor block,");
|
392 | 404 | eprintln!("or otherwise simulating a miner.");
|
393 | 405 | process::exit(1);
|
@@ -523,11 +535,11 @@ pub fn command_try_mine(argv: &[String], conf: Option<&Config>) {
|
523 | 535 | let elapsed = start.elapsed();
|
524 | 536 | let summary = format!(
|
525 | 537 | "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(), |
531 | 543 | );
|
532 | 544 |
|
533 | 545 | let code = match result {
|
@@ -770,7 +782,9 @@ fn replay_block(
|
770 | 782 | ),
|
771 | 783 | None => {
|
772 | 784 | // 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 | + ); |
774 | 788 | }
|
775 | 789 | };
|
776 | 790 |
|
@@ -835,8 +849,10 @@ fn replay_block(
|
835 | 849 | ) {
|
836 | 850 | Ok((receipt, _, _)) => {
|
837 | 851 | 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 | + ); |
840 | 856 | process::exit(1);
|
841 | 857 | }
|
842 | 858 |
|
@@ -1153,7 +1169,9 @@ fn replay_block_nakamoto(
|
1153 | 1169 | // check the cost
|
1154 | 1170 | let evaluated_cost = receipt.anchored_block_cost.clone();
|
1155 | 1171 | 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 | + ); |
1157 | 1175 | process::exit(1);
|
1158 | 1176 | }
|
1159 | 1177 | }
|
@@ -1197,7 +1215,7 @@ pub mod test {
|
1197 | 1215 | "stacks-inspect try-mine --config my_config.toml /tmp/chainstate/mainnet",
|
1198 | 1216 | );
|
1199 | 1217 | let argv_init = argv.clone();
|
1200 |
| - let opts = drain_common_opts(&mut argv, 0); |
| 1218 | + let _opts = drain_common_opts(&mut argv, 0); |
1201 | 1219 | let opts = drain_common_opts(&mut argv, 1);
|
1202 | 1220 |
|
1203 | 1221 | assert_eq!(argv, argv_init);
|
|
0 commit comments