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
42 changes: 41 additions & 1 deletion contrib/clarity-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

use std::io::Write;
use std::io::{Read as _, Write};
use std::path::PathBuf;
use std::{fs, io};

Expand Down Expand Up @@ -114,6 +114,46 @@ fn friendly_expect_opt<A>(input: Option<A>, msg: &str) -> A {
})
}

/// Read text content from a file path or stdin if path is "-"
pub fn read_file_or_stdin(path: &str) -> String {
if path == "-" {
let mut buffer = String::new();
io::stdin()
.read_to_string(&mut buffer)
.expect("Error reading from stdin");
buffer
} else {
fs::read_to_string(path).unwrap_or_else(|e| panic!("Error reading file {path}: {e}"))
}
}

/// Read binary content from a file path or stdin if path is "-"
pub fn read_file_or_stdin_bytes(path: &str) -> Vec<u8> {
if path == "-" {
let mut buffer = vec![];
io::stdin()
.read_to_end(&mut buffer)
.expect("Error reading from stdin");
buffer
} else {
fs::read(path).unwrap_or_else(|e| panic!("Error reading file {path}: {e}"))
}
}

/// Read content from an optional file path, defaulting to stdin if None or "-"
pub fn read_optional_file_or_stdin(path: Option<&PathBuf>) -> String {
match path {
Some(p) => read_file_or_stdin(p.to_str().expect("Invalid UTF-8 in path")),
None => {
let mut buffer = String::new();
io::stdin()
.read_to_string(&mut buffer)
.expect("Error reading from stdin");
buffer
}
}
}

/// Represents an initial allocation entry from JSON
#[derive(Deserialize)]
pub struct InitialAllocation {
Expand Down
33 changes: 3 additions & 30 deletions contrib/clarity-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,47 +14,20 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

use std::io::Read;
use std::path::PathBuf;
use std::{fs, io, process};
use std::process;

use clap::{Parser, Subcommand};
use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier};
use clarity::vm::{ClarityVersion, SymbolicExpression};
use clarity_cli::{
DEFAULT_CLI_EPOCH, execute_check, execute_eval, execute_eval_at_block,
execute_eval_at_chaintip, execute_eval_raw, execute_execute, execute_generate_address,
execute_initialize, execute_launch, execute_repl, vm_execute_in_epoch,
execute_initialize, execute_launch, execute_repl, read_file_or_stdin,
read_optional_file_or_stdin, vm_execute_in_epoch,
};
use stacks_common::types::StacksEpochId;

/// Read content from a file path or stdin if path is "-"
fn read_file_or_stdin(path: &str) -> String {
if path == "-" {
let mut buffer = String::new();
io::stdin()
.read_to_string(&mut buffer)
.expect("Error reading from stdin");
buffer
} else {
fs::read_to_string(path).unwrap_or_else(|e| panic!("Error reading file {path}: {e}"))
}
}

/// Read content from an optional file path, defaulting to stdin if None or "-"
fn read_optional_file_or_stdin(path: Option<&PathBuf>) -> String {
match path {
Some(p) => read_file_or_stdin(p.to_str().expect("Invalid UTF-8 in path")),
None => {
let mut buffer = String::new();
io::stdin()
.read_to_string(&mut buffer)
.expect("Error reading from stdin");
buffer
}
}
}

/// Parse epoch string to StacksEpochId
fn parse_epoch(epoch_str: Option<&String>) -> StacksEpochId {
if let Some(s) = epoch_str {
Expand Down
13 changes: 9 additions & 4 deletions contrib/stacks-inspect/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use std::{fs, io, process};

use clarity::types::chainstate::SortitionId;
use clarity::util::hash::{Sha512Trunc256Sum, to_hex};
use clarity_cli::read_file_or_stdin;
use regex::Regex;
use rusqlite::{Connection, OpenFlags};
use stacks_common::types::chainstate::{BlockHeaderHash, StacksBlockId};
Expand Down Expand Up @@ -773,18 +774,22 @@ pub fn command_contract_hash(argv: &[String], _conf: Option<&Config>) {
let print_help_and_exit = || -> ! {
let n = &argv[0];
eprintln!("Usage:");
eprintln!(" {n} <path-to-contract>");
eprintln!(" {n} <CONTRACT_PATH | - (stdin)>");
process::exit(1);
};

// Process CLI args
let contract_path = argv.get(1).unwrap_or_else(|| print_help_and_exit());
let contract_source = fs::read_to_string(contract_path)
.unwrap_or_else(|e| panic!("Failed to read contract file {contract_path:?}: {e}"));
let contract_source = read_file_or_stdin(contract_path);

let hash = Sha512Trunc256Sum::from_data(contract_source.as_bytes());
let hex_string = to_hex(hash.as_bytes());
println!("Contract hash for {contract_path}:\n{hex_string}");
let source_name = if contract_path == "-" {
"stdin"
} else {
contract_path
};
println!("Contract hash for {source_name}:\n{hex_string}");
}

/// Fetch and process a `StagingBlock` from database and call `replay_block()` to validate
Expand Down
65 changes: 38 additions & 27 deletions contrib/stacks-inspect/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ extern crate stacks_common;
use clarity::consts::CHAIN_ID_MAINNET;
use clarity::types::StacksEpochId;
use clarity::types::chainstate::StacksPrivateKey;
use clarity_cli::DEFAULT_CLI_EPOCH;
use clarity_cli::{DEFAULT_CLI_EPOCH, read_file_or_stdin, read_file_or_stdin_bytes};
use stacks_inspect::{
command_contract_hash, command_replay_mock_mining, command_try_mine, command_validate_block,
drain_common_opts,
Expand Down Expand Up @@ -394,12 +394,21 @@ fn main() {

if argv[1] == "decode-tx" {
if argv.len() < 3 {
eprintln!("Usage: {} decode-tx TRANSACTION", argv[0]);
eprintln!(
"Usage: {} decode-tx <TX_HEX | TX_FILE | - (stdin)>",
argv[0]
);
process::exit(1);
}

let tx_str = &argv[2];
let tx_bytes = hex_bytes(tx_str)
let tx_arg = &argv[2];
let tx_str = if tx_arg == "-" || std::path::Path::new(tx_arg).exists() {
read_file_or_stdin(tx_arg).trim().to_string()
} else {
// Treat as hex string directly
tx_arg.clone()
};
let tx_bytes = hex_bytes(&tx_str)
.map_err(|_e| {
eprintln!("Failed to decode transaction: must be a hex string");
process::exit(1);
Expand Down Expand Up @@ -430,13 +439,12 @@ fn main() {

if argv[1] == "decode-block" {
if argv.len() < 3 {
eprintln!("Usage: {} decode-block BLOCK_PATH", argv[0]);
eprintln!("Usage: {} decode-block <BLOCK_PATH | - (stdin)>", argv[0]);
process::exit(1);
}

let block_path = &argv[2];
let block_data =
fs::read(block_path).unwrap_or_else(|_| panic!("Failed to open {block_path}"));
let block_data = read_file_or_stdin_bytes(block_path);

let block = StacksBlock::consensus_deserialize(&mut io::Cursor::new(&block_data))
.map_err(|_e| {
Expand All @@ -451,12 +459,21 @@ fn main() {

if argv[1] == "decode-nakamoto-block" {
if argv.len() < 3 {
eprintln!("Usage: {} decode-nakamoto-block BLOCK_HEX", argv[0]);
eprintln!(
"Usage: {} decode-nakamoto-block <BLOCK_HEX | HEX_FILE | - (stdin)>",
argv[0]
);
process::exit(1);
}

let block_hex = &argv[2];
let block_data = hex_bytes(block_hex).unwrap_or_else(|_| panic!("Failed to decode hex"));
let block_arg = &argv[2];
let block_hex = if block_arg == "-" || std::path::Path::new(block_arg).exists() {
read_file_or_stdin(block_arg).trim().to_string()
} else {
// Treat as hex string directly
block_arg.clone()
};
let block_data = hex_bytes(&block_hex).unwrap_or_else(|_| panic!("Failed to decode hex"));
let block = NakamotoBlock::consensus_deserialize(&mut io::Cursor::new(&block_data))
.map_err(|_e| {
eprintln!("Failed to decode block");
Expand All @@ -470,11 +487,10 @@ fn main() {

if argv[1] == "decode-net-message" {
let data: String = argv[2].clone();
let buf = if data == "-" {
let mut buffer = vec![];
io::stdin().read_to_end(&mut buffer).unwrap();
buffer
let buf = if data == "-" || std::path::Path::new(&data).exists() {
read_file_or_stdin_bytes(&data)
} else {
// Parse as JSON array of bytes
let data: serde_json::Value = serde_json::from_str(data.as_str()).unwrap();
let data_array = data.as_array().unwrap();
let mut buf = vec![];
Expand Down Expand Up @@ -804,15 +820,14 @@ check if the associated microblocks can be downloaded
if argv[1] == "decode-microblocks" {
if argv.len() < 3 {
eprintln!(
"Usage: {} decode-microblocks MICROBLOCK_STREAM_PATH",
"Usage: {} decode-microblocks <MICROBLOCK_STREAM_PATH | - (stdin)>",
argv[0]
);
process::exit(1);
}

let mblock_path = &argv[2];
let mblock_data =
fs::read(mblock_path).unwrap_or_else(|_| panic!("Failed to open {mblock_path}"));
let mblock_data = read_file_or_stdin_bytes(mblock_path);

let mut cursor = io::Cursor::new(&mblock_data);
let mut debug_cursor = LogReader::from_reader(&mut cursor);
Expand Down Expand Up @@ -1028,7 +1043,7 @@ check if the associated microblocks can be downloaded
if argv[1] == "post-stackerdb" {
if argv.len() < 4 {
eprintln!(
"Usage: {} post-stackerdb slot_id slot_version privkey data",
"Usage: {} post-stackerdb slot_id slot_version privkey <DATA | DATA_FILE | - (stdin)>",
&argv[0]
);
process::exit(1);
Expand All @@ -1038,11 +1053,10 @@ check if the associated microblocks can be downloaded
let privkey: String = argv[4].clone();
let data: String = argv[5].clone();

let buf = if data == "-" {
let mut buffer = vec![];
io::stdin().read_to_end(&mut buffer).unwrap();
buffer
let buf = if data == "-" || std::path::Path::new(&data).exists() {
read_file_or_stdin_bytes(&data)
} else {
// Use the argument directly as data
data.as_bytes().to_vec()
};

Expand Down Expand Up @@ -1221,7 +1235,7 @@ check if the associated microblocks can be downloaded
if argv[1] == "shadow-chainstate-patch" {
if argv.len() < 5 {
eprintln!(
"Usage: {} shadow-chainstate-patch CHAINSTATE_DIR NETWORK SHADOW_BLOCKS_PATH.JSON",
"Usage: {} shadow-chainstate-patch CHAINSTATE_DIR NETWORK <SHADOW_BLOCKS.JSON | - (stdin)>",
&argv[0]
);
process::exit(1);
Expand All @@ -1232,10 +1246,7 @@ check if the associated microblocks can be downloaded
let shadow_blocks_json_path = argv[4].as_str();

let shadow_blocks_hex = {
let mut blocks_json_file =
File::open(shadow_blocks_json_path).expect("Unable to open file");
let mut buffer = vec![];
blocks_json_file.read_to_end(&mut buffer).unwrap();
let buffer = read_file_or_stdin_bytes(shadow_blocks_json_path);
let shadow_blocks_hex: Vec<String> = serde_json::from_slice(&buffer).unwrap();
shadow_blocks_hex
};
Expand Down
Loading