-
Notifications
You must be signed in to change notification settings - Fork 32
Expand file tree
/
Copy pathmain.rs
More file actions
133 lines (121 loc) · 4.15 KB
/
main.rs
File metadata and controls
133 lines (121 loc) · 4.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use std::fmt;
use std::io::{self, Write};
use std::path::PathBuf;
use bitcoin::hashes::Hash;
use bitcoin::hex::DisplayHex;
use bitcoin::taproot::TapLeafHash;
use bitcoin::{ScriptBuf, Transaction};
use clap::Parser;
use bitcoin_scriptexec::*;
#[derive(Parser)]
#[command(author = "Steven Roose <steven@roose.io>", version, about)]
struct Args {
/// filepath to script ASM file
#[arg(required = true)]
script_path: Vec<PathBuf>,
/// Whether to print debug info
#[arg(long)]
debug: bool,
/// Whether to output result in JSON.
#[arg(long)]
json: bool,
}
/// A wrapper for the stack types to print them better.
struct FmtStack<'a>(&'a Stack);
impl fmt::Display for FmtStack<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut iter = self.0.iter_str().rev().peekable();
while let Some(item) = iter.next() {
write!(f, "<{}>", item.as_hex())?;
if iter.peek().is_some() {
write!(f, " ")?;
}
}
Ok(())
}
}
fn inner_main() -> Result<(), String> {
let args = Args::parse();
let mut script = String::new();
for script_path in args.script_path {
let script_asm = std::fs::read_to_string(script_path).expect("error reading script file");
script.push_str(&script_asm);
}
let script = ScriptBuf::from_asm(&script).expect("error parsing script");
println!("Script in hex: {}", script.as_bytes().to_lower_hex_string());
println!("Script size: {} bytes", script.as_bytes().len());
let start = std::time::Instant::now();
let mut exec = Exec::new(
ExecCtx::Tapscript,
Options::default(),
TxTemplate {
tx: Transaction {
version: bitcoin::transaction::Version::TWO,
lock_time: bitcoin::locktime::absolute::LockTime::ZERO,
input: vec![],
output: vec![],
},
prevouts: vec![],
input_idx: 0,
taproot_annex_scriptleaf: Some((TapLeafHash::all_zeros(), None)),
},
script,
vec![],
)
.expect("error creating exec");
const SEP: &str = "--------------------------------------------------";
let mut out = io::stdout();
println!("{}", SEP);
loop {
if args.debug {
if args.json {
let step = json::RunStep {
remaining_script: exec.remaining_script(),
stack: &exec.stack().iter_str().collect::<Vec<Vec<u8>>>(),
altstack: &exec.altstack().iter_str().collect::<Vec<Vec<u8>>>(),
stats: Some(exec.stats()),
};
serde_json::to_writer(&out, &step).expect("I/O error");
out.write_all(&[b'\n']).expect("I/O error");
} else {
println!(
"Remaining script: {}",
exec.remaining_script().to_asm_string()
);
println!("Stack: {}", FmtStack(exec.stack()));
println!("AltStack: {}", FmtStack(exec.altstack()));
println!("{}", SEP);
}
}
if exec.exec_next().is_err() {
break;
}
}
let res = exec.result().unwrap().clone();
if args.json {
let ret = json::RunResult {
success: res.success,
error: res.error.map(|e| format!("{:?}", e)), //TODO(stevenroose) fmt::Display
opcode: res.opcode,
final_stack: &res.final_stack.iter_str().collect::<Vec<Vec<u8>>>(),
stats: Some(exec.stats()),
};
serde_json::to_writer(&out, &ret).expect("I/O error");
} else {
println!("Execution ended. Success: {}", res.success);
print!("Final stack: {}", FmtStack(&res.final_stack));
println!();
if !res.success {
println!("Failed on opcode: {:?}", res.opcode);
println!("Error: {:?}", res.error);
}
println!("Stats:\n{:#?}", exec.stats());
println!("Time elapsed: {}ms", start.elapsed().as_millis());
}
Ok(())
}
fn main() {
if let Err(e) = inner_main() {
eprintln!("ERROR: {}", e);
}
}