forked from BitVM/rust-bitcoin-scriptexec
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.rs
129 lines (117 loc) · 4.05 KB
/
main.rs
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
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 <[email protected]>", version, about)]
struct Args {
/// filepath to script ASM file
#[arg(required = true)]
script_path: 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<'a> fmt::Display for FmtStack<'a> {
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 script_asm = std::fs::read_to_string(args.script_path).expect("error reading script file");
let script = ScriptBuf::parse_asm(&script_asm).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(&['\n' as u8]).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());
}
return Ok(());
}
fn main() {
if let Err(e) = inner_main() {
eprintln!("ERROR: {}", e);
}
}