Pull script tracing code out of Transcation so it can be used independently
This commit is contained in:
parent
611b1f57c9
commit
e3445ebef7
|
@ -114,6 +114,19 @@ pub struct TraceIteration {
|
||||||
stack: Vec<String>
|
stack: Vec<String>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A full trace of a script execution
|
||||||
|
#[deriving(PartialEq, Eq, Show, Clone)]
|
||||||
|
pub struct ScriptTrace {
|
||||||
|
/// A copy of the script
|
||||||
|
pub script: Script,
|
||||||
|
/// A copy of the script's initial stack, hex-encoded
|
||||||
|
pub initial_stack: Vec<String>,
|
||||||
|
/// A list of iterations
|
||||||
|
pub iterations: Vec<TraceIteration>,
|
||||||
|
/// An error if one was returned, or None
|
||||||
|
pub error: Option<ScriptError>
|
||||||
|
}
|
||||||
|
|
||||||
impl_json!(TraceIteration, index, opcode, executed, effect, stack)
|
impl_json!(TraceIteration, index, opcode, executed, effect, stack)
|
||||||
|
|
||||||
/// Hashtype of a transaction, encoded in the last byte of a signature,
|
/// Hashtype of a transaction, encoded in the last byte of a signature,
|
||||||
|
@ -580,6 +593,24 @@ impl Script {
|
||||||
raw.as_slice()
|
raw.as_slice()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trace a script
|
||||||
|
pub fn trace<'a>(&'a self, stack: &mut Vec<MaybeOwned<'a>>,
|
||||||
|
input_context: Option<(&Transaction, uint)>)
|
||||||
|
-> ScriptTrace {
|
||||||
|
let mut trace = ScriptTrace {
|
||||||
|
script: self.clone(),
|
||||||
|
initial_stack: stack.iter().map(|elem| elem.as_slice().to_hex()).collect(),
|
||||||
|
iterations: vec![],
|
||||||
|
error: None
|
||||||
|
};
|
||||||
|
|
||||||
|
match self.evaluate(stack, input_context, Some(&mut trace.iterations)) {
|
||||||
|
Ok(_) => {},
|
||||||
|
Err(e) => { trace.error = Some(e.clone()); }
|
||||||
|
}
|
||||||
|
trace
|
||||||
|
}
|
||||||
|
|
||||||
/// Evaluate the script, modifying the stack in place
|
/// Evaluate the script, modifying the stack in place
|
||||||
pub fn evaluate<'a>(&'a self, stack: &mut Vec<MaybeOwned<'a>>,
|
pub fn evaluate<'a>(&'a self, stack: &mut Vec<MaybeOwned<'a>>,
|
||||||
input_context: Option<(&Transaction, uint)>,
|
input_context: Option<(&Transaction, uint)>,
|
||||||
|
|
|
@ -24,11 +24,10 @@
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use serialize::hex::ToHex;
|
|
||||||
use serialize::json;
|
use serialize::json;
|
||||||
|
|
||||||
use util::hash::Sha256dHash;
|
use util::hash::Sha256dHash;
|
||||||
use blockdata::script::{mod, Script, ScriptError, TraceIteration, read_scriptbool};
|
use blockdata::script::{mod, Script, ScriptError, ScriptTrace, read_scriptbool};
|
||||||
use blockdata::utxoset::UtxoSet;
|
use blockdata::utxoset::UtxoSet;
|
||||||
use network::encodable::ConsensusEncodable;
|
use network::encodable::ConsensusEncodable;
|
||||||
use network::serialize::BitcoinHash;
|
use network::serialize::BitcoinHash;
|
||||||
|
@ -107,15 +106,6 @@ impl json::ToJson for TransactionError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trace of a script execution
|
|
||||||
#[deriving(PartialEq, Eq, Show, Clone)]
|
|
||||||
pub struct ScriptTrace {
|
|
||||||
script: Script,
|
|
||||||
initial_stack: Vec<String>,
|
|
||||||
iterations: Vec<TraceIteration>,
|
|
||||||
error: Option<ScriptError>
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A trace of a transaction input's script execution
|
/// A trace of a transaction input's script execution
|
||||||
#[deriving(PartialEq, Eq, Clone, Show)]
|
#[deriving(PartialEq, Eq, Clone, Show)]
|
||||||
pub struct InputTrace {
|
pub struct InputTrace {
|
||||||
|
@ -223,16 +213,10 @@ impl Transaction {
|
||||||
let mut p2sh_script = Script::new();
|
let mut p2sh_script = Script::new();
|
||||||
|
|
||||||
let mut stack = Vec::with_capacity(6);
|
let mut stack = Vec::with_capacity(6);
|
||||||
trace.sig_trace.script = input.script_sig.clone();
|
trace.sig_trace = input.script_sig.trace(&mut stack, Some((self, n)));
|
||||||
match input.script_sig.evaluate(&mut stack,
|
let err = trace.sig_trace.error.as_ref().map(|e| e.clone());
|
||||||
Some((self, n)),
|
err.map(|e| trace.error = Some(InputScriptFailure(e)));
|
||||||
Some(&mut trace.sig_trace.iterations)) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(e) => {
|
|
||||||
trace.sig_trace.error = Some(e.clone());
|
|
||||||
trace.error = Some(InputScriptFailure(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if txo.script_pubkey.is_p2sh() && stack.len() > 0 {
|
if txo.script_pubkey.is_p2sh() && stack.len() > 0 {
|
||||||
p2sh_stack = stack.clone();
|
p2sh_stack = stack.clone();
|
||||||
p2sh_script = match p2sh_stack.pop() {
|
p2sh_script = match p2sh_stack.pop() {
|
||||||
|
@ -242,21 +226,9 @@ impl Transaction {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if trace.error.is_none() {
|
if trace.error.is_none() {
|
||||||
let mut pk_trace = ScriptTrace {
|
trace.pubkey_trace = Some(txo.script_pubkey.trace(&mut stack, Some((self, n))));
|
||||||
script: txo.script_pubkey.clone(),
|
let err = trace.pubkey_trace.get_ref().error.as_ref().map(|e| e.clone());
|
||||||
initial_stack: stack.iter().map(|elem| elem.as_slice().to_hex()).collect(),
|
err.map(|e| trace.error = Some(OutputScriptFailure(e)));
|
||||||
iterations: vec![],
|
|
||||||
error: None
|
|
||||||
};
|
|
||||||
match txo.script_pubkey.evaluate(&mut stack,
|
|
||||||
Some((self, n)),
|
|
||||||
Some(&mut pk_trace.iterations)) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(e) => {
|
|
||||||
pk_trace.error = Some(e.clone());
|
|
||||||
trace.error = Some(OutputScriptFailure(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
match stack.pop() {
|
match stack.pop() {
|
||||||
Some(v) => {
|
Some(v) => {
|
||||||
if !read_scriptbool(v.as_slice()) {
|
if !read_scriptbool(v.as_slice()) {
|
||||||
|
@ -265,23 +237,10 @@ impl Transaction {
|
||||||
}
|
}
|
||||||
None => { trace.error = Some(ScriptReturnedEmptyStack); }
|
None => { trace.error = Some(ScriptReturnedEmptyStack); }
|
||||||
}
|
}
|
||||||
trace.pubkey_trace = Some(pk_trace);
|
|
||||||
if trace.error.is_none() && txo.script_pubkey.is_p2sh() {
|
if trace.error.is_none() && txo.script_pubkey.is_p2sh() {
|
||||||
let mut p2sh_trace = ScriptTrace {
|
trace.p2sh_trace = Some(p2sh_script.trace(&mut p2sh_stack, Some((self, n))));
|
||||||
script: p2sh_script.clone(),
|
let err = trace.p2sh_trace.get_ref().error.as_ref().map(|e| e.clone());
|
||||||
initial_stack: p2sh_stack.iter().map(|elem| elem.as_slice().to_hex()).collect(),
|
err.map(|e| trace.error = Some(P2shScriptFailure(e)));
|
||||||
iterations: vec![],
|
|
||||||
error: None
|
|
||||||
};
|
|
||||||
match p2sh_script.evaluate(&mut p2sh_stack,
|
|
||||||
Some((self, n)),
|
|
||||||
Some(&mut p2sh_trace.iterations)) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(e) => {
|
|
||||||
p2sh_trace.error = Some(e.clone());
|
|
||||||
trace.error = Some(P2shScriptFailure(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
match p2sh_stack.pop() {
|
match p2sh_stack.pop() {
|
||||||
Some(v) => {
|
Some(v) => {
|
||||||
if !read_scriptbool(v.as_slice()) {
|
if !read_scriptbool(v.as_slice()) {
|
||||||
|
@ -290,7 +249,6 @@ impl Transaction {
|
||||||
}
|
}
|
||||||
None => { trace.error = Some(P2shScriptReturnedEmptyStack); }
|
None => { trace.error = Some(P2shScriptReturnedEmptyStack); }
|
||||||
}
|
}
|
||||||
trace.p2sh_trace = Some(p2sh_trace);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue