From 340b569c733a078ee8cb2b25355bf34d06d238df Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Sun, 31 Aug 2014 09:50:46 -0700 Subject: [PATCH] Add much more agressive provably-false checker Now unspendable outs are determined by attempting to create a minimal satisfying input script. If this can't be done, the output is unspendable. (Unfortunately this "minimal satisfying script" is not (yet) something that can be shown to the user, since it is more a bundle of constraints than actual data pushes.) Current limitations: - OP_ADD and friends mean the checker gives the script a free pass. There is no fundamental reason for this, I just didn't get to it yet. - Pubkeys are checked for DER encoding but signatures aren't. This is because secp256k1 exposes a method for pubkeys, but not one for sigs :). Signatures are loosely length checked. --- src/blockdata/script.rs | 1671 ++++++++++++++++++++++++++++++++------- src/internal_macros.rs | 4 + src/lib.rs | 3 + src/util/hash.rs | 6 + src/wallet/bip32.rs | 2 + 5 files changed, 1421 insertions(+), 265 deletions(-) diff --git a/src/blockdata/script.rs b/src/blockdata/script.rs index 2ffb611..8b5da4e 100644 --- a/src/blockdata/script.rs +++ b/src/blockdata/script.rs @@ -56,6 +56,15 @@ pub struct Script(ThinVec); /// would help you. #[deriving(PartialEq, Eq, Show, Clone)] pub enum ScriptError { + /// The script returns false no matter the input + AnalyzeAlwaysReturnsFalse, + /// Tried to set a boolean to both values, but neither worked + AnalyzeNeitherBoolWorks, + /// Tried to set a boolean to the given value, but it already + /// had the other value + AnalyzeSetBoolMismatch(bool), + /// Validation of an element failed + AnalyzeValidateFailed, /// OP_CHECKSIG was called with a bad public key BadPublicKey, /// OP_CHECKSIG was called with a bad signature @@ -72,6 +81,9 @@ pub enum ScriptError { IfEmptyStack, /// An illegal opcode appeared in the script (does not need to be executed) IllegalOpcode, + /// The interpreter overflowed its stack. This never happens for + /// script evaluation, only non-consensus analysis passes. + InterpreterStackOverflow, /// Some opcode expected a parameter, but it was missing or truncated EarlyEndOfScript, /// An OP_RETURN or synonym was executed @@ -92,12 +104,1093 @@ pub enum ScriptError { NumericOverflow, /// Some stack operation was done with an empty stack PopEmptyStack, + /// Analysis was unable to determine script input + Unanalyzable, + /// Analysis showed script cannot be satisfied + Unsatisfiable, /// An OP_VERIFY happened with an empty stack VerifyEmptyStack, /// An OP_VERIFY happened with zero on the stack VerifyFailed, } +/// A rule for validating an abstract stack element +pub struct Validator { + /// List of other elements to pass to both `check` and `update` + args: Vec, + /// Function which confirms that the current value is consistent with + /// the stack state, returning `false` if not. + check: fn(&AbstractStackElem, &[uint]) -> bool, + /// Function which updates the current stack based on the element's + /// value, if it has a value, otherwise updates the element's value + /// based on the current stack, if possible. Returns `false` if it + /// is forced to do something inconsistent. + update: fn(&mut AbstractStackElem, &[uint]) -> Result<(), ScriptError> +} + +impl Clone for Validator { + fn clone(&self) -> Validator { + Validator { + args: self.args.clone(), + check: self.check, + update: self.update + } + } +} + +// Validators +fn check_op_size(elem: &AbstractStackElem, others: &[uint]) -> bool { + let other = unsafe { elem.lookup(others[0]) }; + elem.num_hi() >= other.len_lo() as i64 && + elem.num_lo() <= other.len_hi() as i64 +} + +fn update_op_size(elem: &mut AbstractStackElem, others: &[uint]) + -> Result<(), ScriptError> { + let (lo, hi) = { + let one = unsafe { elem.lookup(others[0]) }; + (one.len_lo() as i64, one.len_hi() as i64) + }; + try!(elem.set_numeric()); + try!(elem.set_num_lo(lo)); + elem.set_num_hi(hi) +} + +fn check_op_equal(elem: &AbstractStackElem, others: &[uint]) -> bool { + let one = unsafe { elem.lookup(others[0]) }; + let two = unsafe { elem.lookup(others[1]) }; + match elem.bool_value() { + None => true, + Some(false) => { + (one.num_value().is_none() || two.num_value().is_none() || + one.num_value().unwrap() != two.num_value().unwrap()) && + (one.bool_value() != Some(false) || two.bool_value() != Some(false)) && + (one.raw_value().is_none() || two.raw_value().is_none() || + one.raw_value().unwrap() != two.raw_value().unwrap()) + } + Some(true) => { + one.len_lo() <= two.len_hi() && + one.len_hi() >= two.len_lo() && + one.num_lo() <= two.num_hi() && + one.num_hi() >= two.num_lo() && + (one.bool_value().is_none() || two.bool_value().is_none() || + one.bool_value().unwrap() == two.bool_value().unwrap()) && + (one.raw_value().is_none() || two.raw_value().is_none() || + one.raw_value().unwrap() == two.raw_value().unwrap()) + } + } +} + +fn update_boolean(elem: &mut AbstractStackElem) + -> Result<(), ScriptError> { + // Test boolean values + elem.bool_val = Some(true); + let true_works = elem.validate(); + elem.bool_val = Some(false); + let false_works = elem.validate(); + elem.bool_val = None; + // Update according to what worked + match (true_works, false_works) { + (true, true) => Ok(()), + (false, false) => Err(AnalyzeNeitherBoolWorks), + (true, false) => elem.set_bool_value(true), + (false, true) => elem.set_bool_value(false) + } +} + +fn update_op_equal(elem: &mut AbstractStackElem, others: &[uint]) + -> Result<(), ScriptError> { + match elem.bool_value() { + None => update_boolean(elem), + Some(false) => { + let one = unsafe { elem.lookup_mut(others[0]) }; + let two = unsafe { elem.lookup_mut(others[1]) }; + // Booleans are the only thing we can do something useful with re "not equal" + match (one.bool_value(), two.bool_value()) { + (None, None) => Ok(()), + (None, Some(x)) => one.set_bool_value(!x), + (Some(x), None) => two.set_bool_value(!x), + (Some(x), Some(y)) if x == y => Err(Unsatisfiable), + (Some(_), Some(_)) => Ok(()) + } + } + Some(true) => { + let one = unsafe { elem.lookup_mut(others[0]) }; + let two = unsafe { elem.lookup_mut(others[1]) }; + // Equalize numeric bounds + try!(one.set_num_lo(two.num_lo())); + try!(one.set_num_hi(two.num_hi())); + try!(two.set_num_lo(one.num_lo())); + try!(two.set_num_hi(one.num_hi())); + // Equalize boolean values + match (one.bool_value(), two.bool_value()) { + (None, None) => {}, + (None, Some(x)) => try!(one.set_bool_value(x)), + (Some(x), None) => try!(two.set_bool_value(x)), + (Some(x), Some(y)) if x == y => {}, + (Some(_), Some(_)) => { return Err(Unsatisfiable); } + } + // Equalize full values + match (one.raw_value().map(|r| Vec::from_slice(r)), + two.raw_value().map(|r| Vec::from_slice(r))) { + (None, None) => {}, + (None, Some(x)) => try!(one.set_value(x.as_slice())), + (Some(x), None) => try!(two.set_value(x.as_slice())), + (Some(x), Some(y)) => { if x != y { return Err(Unsatisfiable); } } + } + Ok(()) + } + } +} + +fn check_op_not(elem: &AbstractStackElem, others: &[uint]) -> bool { + let one = unsafe { elem.lookup(others[0]) }; + if !one.may_be_numeric() { + return false; + } + + match elem.bool_value() { + None => true, + Some(false) => one.num_hi() != 0 || one.num_lo() != 0, + Some(true) => one.num_hi() >= 0 && one.num_lo() <= 0 + } +} + +fn update_op_not(elem: &mut AbstractStackElem, others: &[uint]) + -> Result<(), ScriptError> { + match elem.bool_value() { + None => update_boolean(elem), + Some(false) => { + let one = unsafe { elem.lookup_mut(others[0]) }; + try!(one.set_numeric()); + match one.bool_value() { + None => one.set_bool_value(true), + Some(true) => Ok(()), + Some(false) => Err(Unsatisfiable) + } + } + Some(true) => { + let one = unsafe { elem.lookup_mut(others[0]) }; + try!(one.set_numeric()); + match one.bool_value() { + None => one.set_num_value(0), + Some(true) => Err(Unsatisfiable), + Some(false) => Ok(()) + } + } + } +} + +fn check_op_0notequal(elem: &AbstractStackElem, others: &[uint]) -> bool { + let one = unsafe { elem.lookup(others[0]) }; + if !one.may_be_numeric() { return false; } + match elem.bool_value() { + None => true, + Some(false) => one.num_hi() >= 0 && one.num_lo() <= 0, + Some(true) => one.num_hi() != 0 || one.num_lo() != 0 + } +} + +fn update_op_0notequal(elem: &mut AbstractStackElem, others: &[uint]) + -> Result<(), ScriptError> { + match elem.bool_value() { + None => update_boolean(elem), + Some(false) => { + let one = unsafe { elem.lookup_mut(others[0]) }; + try!(one.set_numeric()); + match one.bool_value() { + None => one.set_num_value(0), + Some(true) => Err(Unsatisfiable), + Some(false) => Ok(()) + } + } + Some(true) => { + let one = unsafe { elem.lookup_mut(others[0]) }; + try!(one.set_numeric()); + match one.bool_value() { + None => one.set_bool_value(true), + Some(true) => Ok(()), + Some(false) => Err(Unsatisfiable) + } + } + } +} + +fn check_op_numequal(elem: &AbstractStackElem, others: &[uint]) -> bool { + let one = unsafe { elem.lookup(others[0]) }; + let two = unsafe { elem.lookup(others[1]) }; + if !one.may_be_numeric() { return false; } + if !two.may_be_numeric() { return false; } + match elem.bool_value() { + None => true, + Some(false) => { + (one.num_value().is_none() || two.num_value().is_none() || + one.num_value().unwrap() != two.num_value().unwrap()) && + (one.bool_value().is_none() || two.bool_value().is_none() || + one.bool_value().unwrap() != two.bool_value().unwrap()) + } + Some(true) => { + one.num_lo() <= two.num_hi() && + one.num_hi() >= two.num_lo() && + (one.num_value().is_none() || two.num_value().is_none() || + one.num_value().unwrap() == two.num_value().unwrap()) && + (one.bool_value().is_none() || two.bool_value().is_none() || + one.bool_value().unwrap() == two.bool_value().unwrap()) + } + } +} + +fn update_op_numequal(elem: &mut AbstractStackElem, others: &[uint]) + -> Result<(), ScriptError> { + match elem.bool_value() { + None => update_boolean(elem), + Some(false) => { + // todo: find a way to force the numbers to be nonequal + Ok(()) + } + Some(true) => { + let one = unsafe { elem.lookup_mut(others[0]) }; + let two = unsafe { elem.lookup_mut(others[1]) }; + try!(one.set_numeric()); + try!(two.set_numeric()); + try!(one.set_num_lo(two.num_lo())); + try!(one.set_num_hi(two.num_hi())); + try!(two.set_num_lo(one.num_lo())); + two.set_num_hi(one.num_hi()) + } + } +} + +fn check_op_numnotequal(elem: &AbstractStackElem, others: &[uint]) -> bool { + let one = unsafe { elem.lookup(others[0]) }; + let two = unsafe { elem.lookup(others[1]) }; + if !one.may_be_numeric() { return false; } + if !two.may_be_numeric() { return false; } + match elem.bool_value() { + None => true, + Some(false) => one.may_be_lt(two) || one.may_be_gt(two), + Some(true) => one.may_be_lteq(two) && one.may_be_gteq(two) + } +} + +fn update_op_numnotequal(elem: &mut AbstractStackElem, others: &[uint]) + -> Result<(), ScriptError> { + match elem.bool_value() { + None => update_boolean(elem), + Some(false) => { + let one = unsafe { elem.lookup_mut(others[0]) }; + let two = unsafe { elem.lookup_mut(others[1]) }; + try!(one.set_numeric()); + try!(two.set_numeric()); + try!(one.set_num_lo(two.num_lo())); + try!(one.set_num_hi(two.num_hi())); + try!(two.set_num_lo(one.num_lo())); + two.set_num_hi(one.num_hi()) + } + Some(true) => { + // todo: find a way to force the numbers to be nonequal + Ok(()) + } + } +} + +fn check_op_numlt(elem: &AbstractStackElem, others: &[uint]) -> bool { + let one = unsafe { elem.lookup(others[0]) }; + let two = unsafe { elem.lookup(others[1]) }; + if !one.may_be_numeric() { return false; } + if !two.may_be_numeric() { return false; } + match elem.bool_value() { + None => true, + Some(true) => one.may_be_lt(two), + Some(false) => one.may_be_gteq(two), + } +} + +fn update_op_numlt(elem: &mut AbstractStackElem, others: &[uint]) + -> Result<(), ScriptError> { + match elem.bool_value() { + None => update_boolean(elem), + Some(true) => { + let one = unsafe { elem.lookup_mut(others[0]) }; + let two = unsafe { elem.lookup_mut(others[1]) }; + try!(one.set_numeric()); + try!(two.set_numeric()); + + try!(one.set_num_hi(two.num_hi() - 1)); + two.set_num_lo(one.num_lo() + 1) + } + Some(false) => { + let one = unsafe { elem.lookup_mut(others[0]) }; + let two = unsafe { elem.lookup_mut(others[1]) }; + try!(one.set_numeric()); + try!(two.set_numeric()); + + try!(one.set_num_lo(two.num_lo())); + two.set_num_hi(one.num_hi()) + } + } +} + +fn check_op_numgt(elem: &AbstractStackElem, others: &[uint]) -> bool { + let one = unsafe { elem.lookup(others[0]) }; + let two = unsafe { elem.lookup(others[1]) }; + if !one.may_be_numeric() { return false; } + if !two.may_be_numeric() { return false; } + match elem.bool_value() { + None => true, + Some(true) => one.may_be_gt(two), + Some(false) => one.may_be_lteq(two) + } +} + +fn update_op_numgt(elem: &mut AbstractStackElem, others: &[uint]) + -> Result<(), ScriptError> { + match elem.bool_value() { + None => try!(update_boolean(elem)), + Some(true) => { + let one = unsafe { elem.lookup_mut(others[0]) }; + let two = unsafe { elem.lookup_mut(others[1]) }; + try!(one.set_numeric()); + try!(two.set_numeric()); + + try!(one.set_num_lo(two.num_lo() + 1)); + try!(two.set_num_hi(one.num_hi() - 1)); + } + Some(false) => { + let one = unsafe { elem.lookup_mut(others[0]) }; + let two = unsafe { elem.lookup_mut(others[1]) }; + try!(one.set_numeric()); + try!(two.set_numeric()); + + try!(one.set_num_hi(two.num_hi())); + try!(two.set_num_lo(one.num_lo())); + } + } + Ok(()) +} + +fn check_op_numlteq(elem: &AbstractStackElem, others: &[uint]) -> bool { + let one = unsafe { elem.lookup(others[0]) }; + let two = unsafe { elem.lookup(others[1]) }; + if !one.may_be_numeric() { return false; } + if !two.may_be_numeric() { return false; } + match elem.bool_value() { + None => true, + Some(false) => one.may_be_gt(two), + Some(true) => one.may_be_lteq(two) + } +} + +fn update_op_numlteq(elem: &mut AbstractStackElem, others: &[uint]) + -> Result<(), ScriptError> { + match elem.bool_value() { + None => try!(update_boolean(elem)), + Some(true) => { + let one = unsafe { elem.lookup_mut(others[0]) }; + let two = unsafe { elem.lookup_mut(others[1]) }; + try!(one.set_numeric()); + try!(two.set_numeric()); + + try!(one.set_num_hi(two.num_hi())); + try!(two.set_num_lo(one.num_lo())); + } + Some(false) => { + let one = unsafe { elem.lookup_mut(others[0]) }; + let two = unsafe { elem.lookup_mut(others[1]) }; + try!(one.set_numeric()); + try!(two.set_numeric()); + + try!(one.set_num_lo(two.num_lo() + 1)); + try!(two.set_num_hi(one.num_hi() - 1)); + } + } + Ok(()) +} + +fn check_op_numgteq(elem: &AbstractStackElem, others: &[uint]) -> bool { + let one = unsafe { elem.lookup(others[0]) }; + let two = unsafe { elem.lookup(others[1]) }; + if !one.may_be_numeric() { return false; } + if !two.may_be_numeric() { return false; } + match elem.bool_value() { + None => true, + Some(true) => one.may_be_gteq(two), + Some(false) => one.may_be_lt(two) + } +} + +fn update_op_numgteq(elem: &mut AbstractStackElem, others: &[uint]) + -> Result<(), ScriptError> { + match elem.bool_value() { + None => try!(update_boolean(elem)), + Some(true) => { + let one = unsafe { elem.lookup_mut(others[0]) }; + let two = unsafe { elem.lookup_mut(others[1]) }; + try!(one.set_numeric()); + try!(two.set_numeric()); + + try!(one.set_num_lo(two.num_lo())); + try!(two.set_num_hi(one.num_hi())); + } + Some(false) => { + let one = unsafe { elem.lookup_mut(others[0]) }; + let two = unsafe { elem.lookup_mut(others[1]) }; + try!(one.set_numeric()); + try!(two.set_numeric()); + + try!(one.set_num_hi(two.num_hi() - 1)); + try!(two.set_num_lo(one.num_lo() + 1)); + } + } + Ok(()) +} + +fn check_op_ripemd160(elem: &AbstractStackElem, _: &[uint]) -> bool { + elem.may_be_hash160() +} + +fn update_op_ripemd160(elem: &mut AbstractStackElem, others: &[uint]) + -> Result<(), ScriptError> { + try!(elem.set_len_lo(20)); + try!(elem.set_len_hi(20)); + + let hash = match unsafe { elem.lookup(others[0]) }.raw_value() { + None => None, + Some(x) => { + let mut out = [0, ..20]; + let mut engine = Ripemd160::new(); + engine.input(x); + engine.result(out.as_mut_slice()); + Some(out) + } + }; + + match hash { + None => Ok(()), + Some(x) => elem.set_value(x.as_slice()) + } +} + +fn check_op_sha1(elem: &AbstractStackElem, _: &[uint]) -> bool { + elem.may_be_hash160() +} + +fn update_op_sha1(elem: &mut AbstractStackElem, others: &[uint]) + -> Result<(), ScriptError> { + try!(elem.set_len_lo(20)); + try!(elem.set_len_hi(20)); + + let hash = match unsafe { elem.lookup(others[0]) }.raw_value() { + None => None, + Some(x) => { + let mut out = [0, ..20]; + let mut engine = Sha1::new(); + engine.input(x); + engine.result(out.as_mut_slice()); + Some(out) + } + }; + + match hash { + None => Ok(()), + Some(x) => elem.set_value(x.as_slice()) + } +} + +fn check_op_hash160(elem: &AbstractStackElem, _: &[uint]) -> bool { + elem.may_be_hash160() +} + +fn update_op_hash160(elem: &mut AbstractStackElem, others: &[uint]) + -> Result<(), ScriptError> { + try!(elem.set_len_lo(20)); + try!(elem.set_len_hi(20)); + + let hash = match unsafe { elem.lookup(others[0]) }.raw_value() { + None => None, + Some(x) => { + let mut out1 = [0, ..32]; + let mut out2 = [0, ..20]; + let mut engine = Sha256::new(); + engine.input(x); + engine.result(out1.as_mut_slice()); + let mut engine = Ripemd160::new(); + engine.input(out1.as_slice()); + engine.result(out2.as_mut_slice()); + Some(out2) + } + }; + + match hash { + None => Ok(()), + Some(x) => elem.set_value(x.as_slice()) + } +} + +fn check_op_sha256(elem: &AbstractStackElem, _: &[uint]) -> bool { + elem.may_be_hash256() +} + +fn update_op_sha256(elem: &mut AbstractStackElem, others: &[uint]) + -> Result<(), ScriptError> { + try!(elem.set_len_lo(32)); + try!(elem.set_len_hi(32)); + + let hash = match unsafe { elem.lookup(others[0]) }.raw_value() { + None => None, + Some(x) => { + let mut out = [0, ..32]; + let mut engine = Sha256::new(); + engine.input(x); + engine.result(out.as_mut_slice()); + Some(out) + } + }; + + match hash { + None => Ok(()), + Some(x) => elem.set_value(x.as_slice()) + } +} + +fn check_op_hash256(elem: &AbstractStackElem, _: &[uint]) -> bool { + elem.may_be_hash256() +} + +fn update_op_hash256(elem: &mut AbstractStackElem, others: &[uint]) + -> Result<(), ScriptError> { + try!(elem.set_len_lo(32)); + try!(elem.set_len_hi(32)); + + let hash = match unsafe { elem.lookup(others[0]) }.raw_value() { + None => None, + Some(x) => { + let mut out = [0, ..32]; + let mut engine = Sha256::new(); + engine.input(x); + engine.result(out.as_mut_slice()); + let mut engine = Sha256::new(); + engine.input(out.as_slice()); + engine.result(out.as_mut_slice()); + Some(out) + } + }; + + match hash { + None => Ok(()), + Some(x) => elem.set_value(x.as_slice()) + } +} + +fn check_op_checksig(elem: &AbstractStackElem, others: &[uint]) -> bool { + let one = unsafe { elem.lookup(others[0]) }; + let two = unsafe { elem.lookup(others[1]) }; + match elem.bool_value() { + None => true, + Some(false) => true, + Some(true) => one.may_be_signature() && two.may_be_pubkey() + } +} + +fn update_op_checksig(elem: &mut AbstractStackElem, others: &[uint]) + -> Result<(), ScriptError> { + match elem.bool_value() { + None => update_boolean(elem), + Some(false) => Ok(()), // nothing we can do to enforce an invalid sig + Some(true) => { + let sig = unsafe { elem.lookup_mut(others[0]) }; + let pk = unsafe { elem.lookup_mut(others[1]) }; + + // todo add DER encoding enforcement + try!(pk.set_len_lo(33)); + try!(pk.set_len_hi(65)); + try!(sig.set_len_lo(75)); + sig.set_len_hi(80) + } + } +} + +/// An abstract element on the stack, used to describe a satisfying +/// script input +#[deriving(Clone)] +pub struct AbstractStackElem { + /// The raw data, if known + raw: Option>, + /// Boolean value, if forced + bool_val: Option, + /// Lower bound when read as number + num_lo: i64, + /// Upper bound when read as number + num_hi: i64, + /// Length lower bound + len_lo: uint, + /// Length upper bound + len_hi: uint, + /// Relations this must satisfy + validators: Vec, + /// Index of the element in its stack allocator + alloc_index: Option +} + +impl AbstractStackElem { + /// Create a new exact integer + pub fn new_num(n: i64) -> AbstractStackElem { + let raw = build_scriptint(n); + AbstractStackElem { + num_lo: n, + num_hi: n, + len_lo: raw.len(), + len_hi: raw.len(), + raw: Some(raw), + bool_val: Some(n != 0), + validators: vec![], + alloc_index: None + } + } + + /// Create a new exact boolean + pub fn new_bool(b: bool) -> AbstractStackElem { + AbstractStackElem::new_num(if b { 1 } else { 0 }) + } + + /// Create a new exact data + pub fn new_raw(data: &[u8]) -> AbstractStackElem { + let n = read_scriptint(data); + AbstractStackElem { + num_lo: match n { Ok(n) => n, Err(_) => -(1 << 31) }, + num_hi: match n { Ok(n) => n, Err(_) => 1 << 31 }, + len_lo: data.len(), + len_hi: data.len(), + bool_val: Some(read_scriptbool(data)), + raw: Some(Vec::from_slice(data)), + validators: vec![], + alloc_index: None + } + } + + /// Create a new unknown element + pub fn new_unknown() -> AbstractStackElem { + AbstractStackElem { + num_lo: -(1 << 31), + num_hi: 1 << 31, + len_lo: 0, + len_hi: 1 << 20, // blocksize limit + bool_val: None, + raw: None, + validators: vec![], + alloc_index: None + } + } + + /// Looks up another stack item by index + unsafe fn lookup<'a>(&'a self, idx: uint) -> &'a AbstractStackElem { + let mypos = self as *const _; + let myidx = self.alloc_index.unwrap() as int; + &*mypos.offset(idx as int - myidx) + } + + /// Looks up another stack item by index + unsafe fn lookup_mut<'a>(&'a self, idx: uint) -> &'a mut AbstractStackElem { + let mypos = self as *const _ as *mut _; + let myidx = self.alloc_index.unwrap() as int; + &mut *mypos.offset(idx as int - myidx) + } + + /// Retrieve the boolean value of the stack element, if it can be determined + pub fn bool_value(&self) -> Option { + self.bool_val + } + + /// Retrieves the raw value of the stack element, if it can be determined + pub fn raw_value<'a>(&'a self) -> Option<&'a [u8]> { + self.raw.as_ref().map(|x| x.as_slice()) + } + + /// Retrieve the upper bound for this element's numeric value. + /// This can always be determined since there is a fixed upper + /// bound for all numbers. + pub fn num_hi(&self) -> i64 { + self.num_hi + } + + /// Retrieve the lower bound for this element's numeric value. + /// This can always be determined since there is a fixed lower + /// bound for all numbers. + pub fn num_lo(&self) -> i64 { + self.num_lo + } + + /// Retrieve the upper bound for this element's length. This always + /// exists as a finite value, though the default upper limit is some + /// impractically large number + pub fn len_hi(&self) -> uint { + self.len_hi + } + + /// Retrieve the lower bound for this element's length. This always + /// exists since it is at least zero :) + pub fn len_lo(&self) -> uint { + self.len_lo + } + + /// Retries the element's numeric value, if it can be determined + pub fn num_value(&self) -> Option { + let lo = self.num_lo(); + let hi = self.num_hi(); + if lo == hi { Some(lo) } else { None } + } + + /// Propagate any changes to all nodes which are referenced + fn update(&mut self) -> Result<(), ScriptError> { + // Check that this node is consistent before doing any propagation + if !self.validate() { + return Err(AnalyzeValidateFailed); + } + + for v in self.validators.iter().map(|v| v.clone()) { + try!((v.update)(self, v.args.as_slice())); + } + Ok(()) + } + + /// Check that all rules are satisfied + fn validate(&mut self) -> bool { + if self.num_hi < self.num_lo { return false; } + if self.len_hi < self.len_lo { return false; } + + self.validators.iter().all(|rule| (rule.check)(self, rule.args.as_slice())) + } + + /// Sets the boolean value + pub fn set_bool_value(&mut self, val: bool) + -> Result<(), ScriptError> { + match self.bool_val { + Some(x) => { + if x != val { return Err(AnalyzeSetBoolMismatch(val)); } + } + None => { + self.bool_val = Some(val); + if !val { + try!(self.set_num_value(0)); + } else if self.num_lo() == 0 && self.num_hi == 1 { + // This seems like a special case but actually everything that + // is `set_boolean` satisfies it + try!(self.set_num_value(1)); + } + try!(self.update()); + } + } + Ok(()) + } + + /// Sets the numeric value + pub fn set_num_value(&mut self, val: i64) -> Result<(), ScriptError> { + try!(self.set_num_lo(val)); + self.set_num_hi(val) + } + + /// Sets the entire value of the + pub fn set_value(&mut self, val: &[u8]) -> Result<(), ScriptError> { + match self.raw_value().map(|x| Vec::from_slice(x)) { + Some(x) => { if x.as_slice() == val { Ok(()) } else { Err(Unsatisfiable) } } + None => { + try!(self.set_len_lo(val.len())); + try!(self.set_len_hi(val.len())); + try!(self.set_bool_value(read_scriptbool(val))); + match read_scriptint(val) { + Ok(n) => { + try!(self.set_num_lo(n)); + try!(self.set_num_hi(n)); + } + Err(_) => {} + } + try!(self.set_bool_value(read_scriptbool(val))); + self.raw = Some(Vec::from_slice(val)); + Ok(()) + } + } + } + + /// Sets a number to be numerically parseable + pub fn set_numeric(&mut self) -> Result<(), ScriptError> { + self.set_len_hi(4) + } + + /// Whether an element could possibly be a number + pub fn may_be_numeric(&self) -> bool { + self.len_lo() <= 4 + } + + /// Whether an element could possibly be a signature + pub fn may_be_signature(&self) -> bool { + self.len_lo() <= 78 && self.len_hi() >= 77 + // todo check DER encoding + } + + /// Whether an element could possibly be a pubkey + pub fn may_be_pubkey(&self) -> bool { + ((self.len_lo() <= 33 && self.len_hi() >= 33) || + (self.len_lo() <= 65 && self.len_hi() >= 65)) && + (self.raw_value().is_none() || PublicKey::from_slice(self.raw_value().unwrap()).is_ok()) + } + + /// Whether an element could possibly be less than another + pub fn may_be_lt(&self, other: &AbstractStackElem) -> bool { + self.num_lo() < other.num_hi() && + (self.num_value().is_none() || other.num_value().is_none() || + self.num_value().unwrap() < other.num_value().unwrap()) && + (self.bool_value().is_none() || other.bool_value().is_none() || + self.bool_value().unwrap() < other.bool_value().unwrap()) + } + + /// Whether an element could possibly be greater than another + pub fn may_be_gt(&self, other: &AbstractStackElem) -> bool { + self.num_hi() > other.num_lo() && + (self.num_value().is_none() || other.num_value().is_none() || + self.num_value().unwrap() > other.num_value().unwrap()) && + (self.bool_value().is_none() || other.bool_value().is_none() || + self.bool_value().unwrap() >= other.bool_value().unwrap()) + } + + /// Whether an element could possibly be less than or equal to another + pub fn may_be_lteq(&self, other: &AbstractStackElem) -> bool { + self.num_lo() <= other.num_hi() && + (self.num_value().is_none() || other.num_value().is_none() || + self.num_value().unwrap() <= other.num_value().unwrap()) && + (self.bool_value().is_none() || other.bool_value().is_none() || + self.bool_value().unwrap() <= other.bool_value().unwrap()) + } + + /// Whether an element could possibly be greater than or equal to another + pub fn may_be_gteq(&self, other: &AbstractStackElem) -> bool { + self.num_hi() >= other.num_lo() && + (self.num_value().is_none() || other.num_value().is_none() || + self.num_value().unwrap() >= other.num_value().unwrap()) && + (self.bool_value().is_none() || other.bool_value().is_none() || + self.bool_value().unwrap() >= other.bool_value().unwrap()) + } + + /// Whether an element could possibly be a 20-byte hash + pub fn may_be_hash160(&self) -> bool { + self.len_lo() <= 20 && self.len_hi() >= 20 + } + + /// Whether an element could possibly be a 32-byte hash + pub fn may_be_hash256(&self) -> bool { + self.len_lo() <= 32 && self.len_hi() >= 32 + } + + /// Sets a number to be an opcode-pushed boolean + pub fn set_boolean(&mut self) -> Result<(), ScriptError> { + try!(self.set_len_hi(1)); + try!(self.set_num_lo(0)); + self.set_num_hi(1) + } + + /// Sets a numeric lower bound on a value + pub fn set_num_lo(&mut self, value: i64) -> Result<(), ScriptError> { + if self.num_lo < value { + self.num_lo = value; + if value > 0 { try!(self.set_bool_value(true)); } + if value == 0 && self.num_hi == 0 { try!(self.set_bool_value(false)); } + try!(self.update()); + } + Ok(()) + } + + /// Sets a numeric upper bound on a value + pub fn set_num_hi(&mut self, value: i64) -> Result<(), ScriptError> { + if self.num_hi > value { + self.num_hi = value; + if value < 0 { try!(self.set_bool_value(true)); } + if value == 0 && self.num_lo == 0 { try!(self.set_bool_value(false)); } + try!(self.update()); + } + Ok(()) + } + + /// Sets a lower length bound on a value + pub fn set_len_lo(&mut self, value: uint) -> Result<(), ScriptError> { + if self.len_lo < value { + self.len_lo = value; + if value > 0 { try!(self.set_bool_value(true)); } + if value == 0 && self.num_hi == 0 { try!(self.set_bool_value(false)); } + try!(self.update()); + } + Ok(()) + } + + /// Sets a upper length bound on a value + pub fn set_len_hi(&mut self, value: uint) -> Result<(), ScriptError> { + if self.len_hi > value { + self.len_hi = value; + try!(self.update()); + } + Ok(()) + } + + /// Adds some condition on the element + pub fn add_validator(&mut self, cond: Validator) -> Result<(), ScriptError> { + self.validators.push(cond); + self.update() + } +} + + +/// The stack used by the script satisfier +#[deriving(Clone)] +pub struct AbstractStack { + /// Actual elements on the stack + stack: Vec, + /// Actual elements on the altstack + alt_stack: Vec, + /// Stack needed to satisfy the script before execution + initial_stack: Vec, + /// Local allocator to allow cloning; refs are indices into here + alloc: Vec +} + +impl AbstractStack { + /// Construct a new empty abstract stack + pub fn new() -> AbstractStack { + AbstractStack { + stack: vec![], + alt_stack: vec![], + initial_stack: vec![], + alloc: vec![] + } + } + + fn allocate(&mut self, mut elem: AbstractStackElem) -> uint { + elem.alloc_index = Some(self.alloc.len()); + self.alloc.push(elem); + self.alloc.len() - 1 + } + + fn push_initial(&mut self, elem: AbstractStackElem) { + let idx = self.allocate(elem); + self.initial_stack.push(idx); + self.stack.insert(0, idx); + } + + /// Construct the initial stack in the end + pub fn build_initial_stack(&self) -> Vec { + let mut res: Vec = + self.initial_stack.iter().map(|&i| self.alloc[i].clone()).collect(); + res.reverse(); + res + } + + /// Increase the stack size to `n`, adding elements to the initial + /// stack as necessary + pub fn require_n_elems(&mut self, n: uint) { + while self.stack.len() < n { + self.push_initial(AbstractStackElem::new_unknown()); + } + } + + /// Lookup an element by index + pub fn get_elem(&self, alloc_index: uint) -> &AbstractStackElem { + &self.alloc[alloc_index] + } + + /// Lookup an element by index + pub fn get_elem_mut(&mut self, alloc_index: uint) -> &mut AbstractStackElem { + self.alloc.get_mut(alloc_index) + } + + /// Push a copy of an existing element by index + pub fn push(&mut self, elem: uint) { + self.stack.push(elem); + } + + /// Push a new element + pub fn push_alloc<'a>(&'a mut self, elem: AbstractStackElem) -> &'a mut AbstractStackElem { + let idx = self.allocate(elem); + self.stack.push(idx); + self.alloc.get_mut(idx) + } + + + /// Obtain a mutable element to the top stack element + pub fn peek_mut<'a>(&'a mut self) -> &'a mut AbstractStackElem { + if self.stack.len() == 0 { + self.push_initial(AbstractStackElem::new_unknown()); + } + + self.alloc.get_mut(*self.stack.last().unwrap()) + } + + /// Obtain a stackref to the current top element + pub fn peek_index(&mut self) -> uint { + if self.stack.len() == 0 { + self.push_initial(AbstractStackElem::new_unknown()); + } + *self.stack.last().unwrap() + } + + /// Drop the top stack item + fn pop(&mut self) -> uint { + if self.stack.len() == 0 { + self.push_initial(AbstractStackElem::new_unknown()); + } + self.stack.pop().unwrap() + } + + /// Obtain a mutable reference to the top stack item, but remove it from the stack + fn pop_mut<'a>(&'a mut self) -> &'a mut AbstractStackElem { + if self.stack.len() == 0 { + self.push_initial(AbstractStackElem::new_unknown()); + } + + self.alloc.get_mut(self.stack.pop().unwrap()) + } + + + /// Move the top stack item to the altstack + pub fn to_altstack(&mut self) { + if self.stack.len() == 0 { + self.push_initial(AbstractStackElem::new_unknown()); + } + + let pop = self.stack.pop().unwrap(); + self.alt_stack.push(pop); + } + + /// Move the top altstack item to the stack, failing if the + /// altstack is empty. (Note that input scripts pass their + /// stack to the output script but /not/ the altstack, so + /// there is no input that can make an empty altstack nonempty.) + pub fn from_altstack(&mut self) -> Result<(), ScriptError> { + match self.alt_stack.pop() { + Some(x) => { self.stack.push(x); Ok(()) } + None => Err(PopEmptyStack) + } + } + + /// Immutable view of the current stack as a slice (to be compatible + /// with the `stack_opcode!` macro + pub fn as_slice<'a>(&'a self) -> &'a [uint] { + self.stack.as_slice() + } + + /// Mutable view of the current stack as a slice (to be compatible + /// with the `stack_opcode!` macro + fn as_mut_slice<'a>(&'a mut self) -> &'a mut [uint] { + self.stack.as_mut_slice() + } + + /// Length of the current stack + fn len(&self) -> uint { + self.stack.len() + } + + /// Delete an element from the middle of the current stack + fn remove(&mut self, idx: uint) { + self.stack.remove(idx); + } +} + impl json::ToJson for ScriptError { fn to_json(&self) -> json::Json { json::String(self.to_string()) @@ -200,8 +1293,8 @@ impl<'a> Collection for MaybeOwned<'a> { } } -static script_true: &'static [u8] = &[0x01]; -static script_false: &'static [u8] = &[0x00]; +static SCRIPT_TRUE: &'static [u8] = &[0x01]; +static SCRIPT_FALSE: &'static [u8] = &[0x00]; /// Helper to encode an integer in script format fn build_scriptint(n: i64) -> Vec { @@ -261,7 +1354,9 @@ pub fn read_scriptint(v: &[u8]) -> Result { /// else as true", except that the overflow rules don't apply. #[inline] pub fn read_scriptbool(v: &[u8]) -> bool { - !v.iter().all(|&w| w == 0) + !(v.len() == 0 || + ((v[v.len() - 1] == 0 || v[v.len() - 1] == 0x80) && + v.iter().rev().skip(1).all(|&w| w == 0))) } /// Read a script-encoded unsigned integer @@ -308,7 +1403,7 @@ fn check_signature(secp: &Secp256k1, sig_slice: &[u8], pk_slice: &[u8], script: // For anyone-can-pay transactions we replace the whole input array // with just the current input, to ensure the others have no effect. let mut old_input = tx.input[input_index].clone(); - old_input.script_sig = Script(ThinVec::from_vec(script.take_unwrap())); + old_input.script_sig = Script(ThinVec::from_vec(script.take().unwrap())); tx_copy.input = vec![old_input]; } else { // Otherwise we keep all the inputs, blanking out the others and even @@ -320,7 +1415,7 @@ fn check_signature(secp: &Secp256k1, sig_slice: &[u8], pk_slice: &[u8], script: sequence: input.sequence, script_sig: Script::new() }; if n == input_index { - new_input.script_sig = Script(ThinVec::from_vec(script.take_unwrap())); + new_input.script_sig = Script(ThinVec::from_vec(script.take().unwrap())); } else { new_input.script_sig = Script::new(); // If we aren't signing them, also zero out the sequence number @@ -379,17 +1474,19 @@ fn check_signature(secp: &Secp256k1, sig_slice: &[u8], pk_slice: &[u8], script: // like. macro_rules! stack_opcode( ($stack:ident($min:expr): + $(require $r:expr)* $(copy $c:expr)* $(swap ($a:expr, $b:expr))* $(perm ($first:expr $(->$i:expr)*) )* $(drop $d:expr)* ) => ({ + $( $stack.require_n_elems($r); )* // Record top let top = $stack.len(); // Check stack size if top < $min { return Err(PopEmptyStack); } // Do copies - $( let elem = (*$stack)[top - $c].clone(); + $( let elem = $stack.as_slice()[top - $c].clone(); $stack.push(elem); )* // Do swaps $( $stack.as_mut_slice().swap(top - $a, top - $b); )* @@ -401,34 +1498,6 @@ macro_rules! stack_opcode( }); ) -macro_rules! stack_opcode_provable( - ($stack:ident($min:expr): - $(copy $c:expr)* - $(swap ($a:expr, $b:expr))* - $(perm ($first:expr $(->$i:expr)*) )* - $(drop $d:expr)* - ) => ({ - // Record top - let top = $stack.len(); - // Do copies -- if we can't copy, and there is anything on the stack, return - // "not unspendable" since we can no longer predict the top of the stack - $( if top >= $c { - let elem = $stack[top - $c].clone(); - $stack.push(elem); - } else if top > 0 { return false; } )* - // Do swaps -- if we can't, return "not unspendable" - $( if top >= $a && top >= $b { $stack.as_mut_slice().swap(top - $a, top - $b); } - else if top > 0 { return false; } )* - // Do permutations -- if we can't, return "not unspendable" - if top >= $min { - $( let first = $first; - $( $stack.as_mut_slice().swap(top - first, top - $i); )* )* - } else if top > 0 { return false; } - // Do drops last so that dropped values will be available above - $( if top >= $d { $stack.remove(top - $d); } )* - }); -) - /// Macro to translate numerical operations into stack ones macro_rules! num_opcode( ($stack:ident($($var:ident),*): $op:expr) => ({ @@ -444,23 +1513,43 @@ macro_rules! num_opcode( }); ) -macro_rules! num_opcode_provable( - ($stack:ident($($var:ident),*): $op:expr) => ({ - let mut failed = false; - $( - let $var = match read_scriptint(match $stack.pop() { - Some(elem) => elem, - // Out of stack elems: fine, just don't push a new one - None => { failed = true; Slice(script_false) } - }.as_slice()) { - Ok(n) => n, - // Overflow is overflow, "provably unspendable" - Err(_) => { return true; } - }; - )* - if !failed { - $stack.push(Owned(build_scriptint($op))); - } +macro_rules! unary_opcode_satisfy( + ($stack:ident, $op:ident) => ({ + let one = $stack.pop(); + let cond = $stack.push_alloc(AbstractStackElem::new_unknown()); + try!(cond.add_validator(Validator { args: vec![one], + check: concat_idents!(check_, $op), + update: concat_idents!(update_, $op) })); + }) +) + +macro_rules! boolean_opcode_satisfy( + ($stack:ident, unary $op:ident) => ({ + let one = $stack.pop(); + let cond = $stack.push_alloc(AbstractStackElem::new_unknown()); + try!(cond.set_boolean()); + try!(cond.add_validator(Validator { args: vec![one], + check: concat_idents!(check_, $op), + update: concat_idents!(update_, $op) })); + }); + ($stack:ident, binary $op:ident) => ({ + let one = $stack.pop(); + let two = $stack.pop(); + let cond = $stack.push_alloc(AbstractStackElem::new_unknown()); + try!(cond.set_boolean()); + try!(cond.add_validator(Validator { args: vec![two, one], + check: concat_idents!(check_, $op), + update: concat_idents!(update_, $op) })); + }); + ($stack:ident, ternary $op:ident) => ({ + let one = $stack.pop(); + let two = $stack.pop(); + let three = $stack.pop(); + let mut cond = $stack.push_alloc(AbstractStackElem::new_unknown()); + try!(cond.set_boolean()); + try!(cond.add_validator(Validator { args: vec![three, two, one], + check: concat_idents!(check_, $op), + update: concat_idents!(update_, $op) })); }); ) @@ -483,24 +1572,6 @@ macro_rules! hash_opcode( }); ) -macro_rules! hash_opcode_provable( - ($stack:ident, $hash:ident) => ({ - match $stack.pop() { - None => { } - Some(v) => { - let mut engine = $hash::new(); - engine.input(v.as_slice()); - let mut ret = Vec::with_capacity(engine.output_bits() / 8); - // Force-set the length even though the vector is uninitialized - // This is OK only because u8 has no destructor - unsafe { ret.set_len(engine.output_bits() / 8); } - engine.result(ret.as_mut_slice()); - $stack.push(Owned(ret)); - } - } - }); -) - // OP_VERIFY macro macro_rules! op_verify ( ($stack:expr, $err:expr) => ( @@ -512,14 +1583,11 @@ macro_rules! op_verify ( ) ) -macro_rules! op_verify_provable ( - ($stack:expr) => ( - match $stack.last().map(|v| read_scriptbool(v.as_slice())) { - None => { } - Some(false) => { return true; } - Some(true) => { $stack.pop(); } - } - ) +macro_rules! op_verify_satisfy ( + ($stack:expr) => ({ + try!($stack.peek_mut().set_bool_value(true)); + $stack.pop(); + }) ) impl Script { @@ -795,7 +1863,7 @@ impl Script { if stack.len() < 2 { return Err(PopEmptyStack); } let a = stack.pop().unwrap(); let b = stack.pop().unwrap(); - stack.push(Slice(if a == b { script_true } else { script_false })); + stack.push(Slice(if a == b { SCRIPT_TRUE } else { SCRIPT_FALSE })); if op == opcodes::OP_EQUALVERIFY { op_verify!(stack, EqualVerifyFailed(a.as_slice().to_hex(), b.as_slice().to_hex())); @@ -858,8 +1926,8 @@ impl Script { let (tx, input_index) = input_context.unwrap(); match check_signature(&secp, sig_slice, pk_slice, script, tx, input_index) { - Ok(()) => stack.push(Slice(script_true)), - _ => stack.push(Slice(script_false)), + Ok(()) => stack.push(Slice(SCRIPT_TRUE)), + _ => stack.push(Slice(SCRIPT_FALSE)), } if op == opcodes::OP_CHECKSIGVERIFY { op_verify!(stack, VerifyFailed); } } @@ -927,12 +1995,12 @@ impl Script { } // Run out of signatures, success (_, None) => { - stack.push(Slice(script_true)); + stack.push(Slice(SCRIPT_TRUE)); break; } // Run out of keys to match to signatures, fail (None, Some(_)) => { - stack.push(Slice(script_false)); + stack.push(Slice(SCRIPT_FALSE)); break; } } @@ -965,65 +2033,84 @@ impl Script { } } + /// Whether a script can be proven to have no satisfying input + pub fn is_provably_unspendable(&self) -> bool { + match self.satisfy() { + Ok(_) => false, + Err(Unanalyzable) => false, + Err(x) => { +//println!("ispu ret {}", x); + true + } + } + } + /// Evaluate the script to determine whether any possible input will cause it /// to accept. Returns true if it is guaranteed to fail; false otherwise. - pub fn is_provably_unspendable(&self) -> bool { - let &Script(ref raw) = self; - - fn recurse<'a>(script: &'a [u8], mut stack: Vec>, depth: uint) -> bool { + pub fn satisfy(&self) -> Result, ScriptError> { + fn recurse<'a>(script: &'a [u8], + mut stack: AbstractStack, + depth: uint) -> Result, ScriptError> { let mut exec_stack = vec![true]; - let mut alt_stack = vec![]; // Avoid doing more than 64k forks - if depth > 16 { return false; } + if depth > 16 { return Err(InterpreterStackOverflow); } let mut index = 0; while index < script.len() { let executing = exec_stack.iter().all(|e| *e); let byte = script[index]; index += 1; - // The definitions of all these categories are in opcodes.rs -//println!("read {} as {} as {} ... stack before op is {}", byte, allops::Opcode::from_u8(byte), allops::Opcode::from_u8(byte).classify(), stack); + // The definitions of all these categories are in opcodes.rs +//println!("read {} as {} as {}", byte, allops::Opcode::from_u8(byte), allops::Opcode::from_u8(byte).classify()); match (executing, allops::Opcode::from_u8(byte).classify()) { // Illegal operations mean failure regardless of execution state - (_, opcodes::IllegalOp) => { return true; } + (_, opcodes::IllegalOp) => return Err(IllegalOpcode), // Push number - (true, opcodes::PushNum(n)) => stack.push(Owned(build_scriptint(n as i64))), + (true, opcodes::PushNum(n)) => { stack.push_alloc(AbstractStackElem::new_num(n as i64)); }, // Return operations mean failure, but only if executed - (true, opcodes::ReturnOp) => { return true; } + (true, opcodes::ReturnOp) => return Err(ExecutedReturn), // Data-reading statements still need to read, even when not executing (_, opcodes::PushBytes(n)) => { - if script.len() < index + n { return true; } - if executing { stack.push(Slice(script.slice(index, index + n))); } + if script.len() < index + n { return Err(EarlyEndOfScript); } + if executing { + stack.push_alloc(AbstractStackElem::new_raw(script.slice(index, index + n))); + } index += n; } (_, opcodes::Ordinary(opcodes::OP_PUSHDATA1)) => { - if script.len() < index + 1 { return true; } + if script.len() < index + 1 { return Err(EarlyEndOfScript); } let n = match read_uint(script.slice_from(index).iter(), 1) { Ok(n) => n, - Err(_) => { return true; } + Err(_) => { return Err(EarlyEndOfScript); } }; - if script.len() < index + 1 + n { return true; } - if executing { stack.push(Slice(script.slice(index + 1, index + n + 1))); } + if script.len() < index + 1 + n { return Err(EarlyEndOfScript); } + if executing { + stack.push_alloc(AbstractStackElem::new_raw(script.slice(index + 1, index + n + 1))); + } index += 1 + n; } (_, opcodes::Ordinary(opcodes::OP_PUSHDATA2)) => { - if script.len() < index + 2 { return true; } + if script.len() < index + 2 { return Err(EarlyEndOfScript); } let n = match read_uint(script.slice_from(index).iter(), 2) { Ok(n) => n, - Err(_) => { return true; } + Err(_) => { return Err(EarlyEndOfScript); } }; - if script.len() < index + 2 + n { return true; } - if executing { stack.push(Slice(script.slice(index + 2, index + n + 2))); } + if script.len() < index + 2 + n { return Err(EarlyEndOfScript); } + if executing { + stack.push_alloc(AbstractStackElem::new_raw(script.slice(index + 2, index + n + 2))); + } index += 2 + n; } (_, opcodes::Ordinary(opcodes::OP_PUSHDATA4)) => { let n = match read_uint(script.slice_from(index).iter(), 4) { Ok(n) => n, - Err(_) => { return true; } + Err(_) => { return Err(EarlyEndOfScript); } }; - if script.len() < index + 4 + n { return true; } - if executing { stack.push(Slice(script.slice(index + 4, index + n + 4))); } + if script.len() < index + 4 + n { return Err(EarlyEndOfScript); } + if executing { + stack.push_alloc(AbstractStackElem::new_raw(script.slice(index + 4, index + n + 4))); + } index += 4 + n; } // If-statements take effect when not executing @@ -1032,12 +2119,12 @@ impl Script { (false, opcodes::Ordinary(opcodes::OP_ELSE)) => { match exec_stack.mut_last() { Some(ref_e) => { *ref_e = !*ref_e } - None => { return true; } + None => { return Err(ElseWithoutIf); } } } (false, opcodes::Ordinary(opcodes::OP_ENDIF)) => { if exec_stack.pop().is_none() { - return true; + return Err(EndifWithoutIf); } } // No-ops and non-executed operations do nothing @@ -1049,201 +2136,237 @@ impl Script { // handled above } opcodes::OP_IF => { - match stack.pop().map(|v| read_scriptbool(v.as_slice())) { + let top_bool = { + let top = stack.peek_mut(); + top.bool_value() + }; + match top_bool { None => { let mut stack_true = stack.clone(); - stack_true.push(Slice(script_true)); - stack.push(Slice(script_false)); - return recurse(script.slice_from(index - 1), stack, depth + 1) && - recurse(script.slice_from(index - 1), stack_true, depth + 1); + // Try pushing false and see what happens + if stack.peek_mut().set_bool_value(false).is_ok() { + match recurse(script.slice_from(index - 1), stack, depth + 1) { + Ok(res) => { return Ok(res); } + Err(_) => {} + } + } + // Failing that, push true + try!(stack_true.peek_mut().set_bool_value(true)); + return recurse(script.slice_from(index - 1), stack_true, depth + 1); + } + Some(val) => { + stack.pop(); + exec_stack.push(val) } - Some(b) => exec_stack.push(b) } } opcodes::OP_NOTIF => { - match stack.pop().map(|v| read_scriptbool(v.as_slice())) { + let top_bool = { + let top = stack.peek_mut(); + top.bool_value() + }; + match top_bool { None => { let mut stack_true = stack.clone(); - stack_true.push(Slice(script_true)); - stack.push(Slice(script_false)); - return recurse(script.slice_from(index - 1), stack, depth + 1) && - recurse(script.slice_from(index - 1), stack_true, depth + 1); + // Try pushing false and see what happens + if stack.peek_mut().set_bool_value(false).is_ok() { + match recurse(script.slice_from(index - 1), stack, depth + 1) { + Ok(res) => { return Ok(res); } + Err(_) => {} + } + } + // Failing that, push true + try!(stack_true.peek_mut().set_bool_value(true)); + return recurse(script.slice_from(index - 1), stack_true, depth + 1); + } + Some(val) => { + stack.pop(); + exec_stack.push(!val) } - Some(b) => exec_stack.push(!b), } } opcodes::OP_ELSE => { match exec_stack.mut_last() { Some(ref_e) => { *ref_e = !*ref_e } - None => { return true; } + None => { return Err(ElseWithoutIf); } } } opcodes::OP_ENDIF => { if exec_stack.pop().is_none() { - return true; + return Err(EndifWithoutIf); } } - opcodes::OP_VERIFY => op_verify_provable!(stack), - opcodes::OP_TOALTSTACK => { stack.pop().map(|elem| alt_stack.push(elem)); } - opcodes::OP_FROMALTSTACK => { alt_stack.pop().map(|elem| stack.push(elem)); } - opcodes::OP_2DROP => stack_opcode_provable!(stack(2): drop 1 drop 2), - opcodes::OP_2DUP => stack_opcode_provable!(stack(2): copy 2 copy 1), - opcodes::OP_3DUP => stack_opcode_provable!(stack(3): copy 3 copy 2 copy 1), - opcodes::OP_2OVER => stack_opcode_provable!(stack(4): copy 4 copy 3), - opcodes::OP_2ROT => stack_opcode_provable!(stack(6): perm (1 -> 3 -> 5) - perm (2 -> 4 -> 6)), - opcodes::OP_2SWAP => stack_opcode_provable!(stack(4): swap (2, 4) - swap (1, 3)), - opcodes::OP_DROP => stack_opcode_provable!(stack(1): drop 1), - opcodes::OP_DUP => stack_opcode_provable!(stack(1): copy 1), - opcodes::OP_NIP => stack_opcode_provable!(stack(2): drop 2), - opcodes::OP_OVER => stack_opcode_provable!(stack(2): copy 2), + opcodes::OP_VERIFY => op_verify_satisfy!(stack), + opcodes::OP_TOALTSTACK => { stack.to_altstack(); } + opcodes::OP_FROMALTSTACK => { try!(stack.from_altstack()); } + opcodes::OP_2DROP => stack_opcode!(stack(2): require 2 drop 1 drop 2), + opcodes::OP_2DUP => stack_opcode!(stack(2): require 2 copy 2 copy 1), + opcodes::OP_3DUP => stack_opcode!(stack(3): require 3 copy 3 copy 2 copy 1), + opcodes::OP_2OVER => stack_opcode!(stack(4): require 4 copy 4 copy 3), + opcodes::OP_2ROT => stack_opcode!(stack(6): require 6 + perm (1 -> 3 -> 5) + perm (2 -> 4 -> 6)), + opcodes::OP_2SWAP => stack_opcode!(stack(4): require 4 + swap (2, 4) + swap (1, 3)), + opcodes::OP_DROP => stack_opcode!(stack(1): require 1 drop 1), + opcodes::OP_DUP => stack_opcode!(stack(1): require 1 copy 1), + opcodes::OP_NIP => stack_opcode!(stack(2): require 2 drop 2), + opcodes::OP_OVER => stack_opcode!(stack(2): require 2 copy 2), opcodes::OP_PICK => { - let n = match stack.pop() { - Some(data) => match read_scriptint(data.as_slice()) { - Ok(n) => n, - Err(_) => { return true; } - }, - None => { return false; } + let top_n = { + let top = stack.peek_mut(); + try!(top.set_numeric()); + try!(top.set_num_lo(0)); + top.num_value().map(|n| n as uint) }; - if n < 0 { return true; } - let n = n as uint; - stack_opcode_provable!(stack(n + 1): copy n + 1) + stack.pop(); + match top_n { + Some(n) => stack_opcode!(stack(n + 1): require n + 1 copy n + 1), + // The stack will wind up with the 1 and nth inputs being identical + // with n input-dependent. I can imagine scripts which check this + // condition or its negation for various n to get arbitrary finite + // sets of allowable values. It's not clear to me that this is + // feasible to analyze. + None => { return Err(Unanalyzable); } + } } opcodes::OP_ROLL => { - let n = match stack.pop() { - Some(data) => match read_scriptint(data.as_slice()) { - Ok(n) => n, - Err(_) => { return true; } - }, - None => { return false; } + let top_n = { + let top = stack.peek_mut(); + try!(top.set_numeric()); + try!(top.set_num_lo(0)); + top.num_value().map(|n| n as uint) }; - if n < 0 { return true; } - let n = n as uint; - stack_opcode_provable!(stack(n + 1): copy n + 1 drop n + 1) + stack.pop(); + match top_n { + Some(n) => stack_opcode!(stack(n + 1): require n + 1 copy n + 1 drop n + 1), + // The stack will wind up reordered, so in principle I could just force + // the input to be zero (other n values can be converted to zero by just + // manually rearranging the input). The problem is if numeric bounds are + // later set on n. I can't analyze that. + None => { return Err(Unanalyzable); } + } } - opcodes::OP_ROT => stack_opcode_provable!(stack(3): perm (1 -> 2 -> 3)), - opcodes::OP_SWAP => stack_opcode_provable!(stack(2): swap (1, 2)), - opcodes::OP_TUCK => stack_opcode_provable!(stack(2): copy 2 copy 1 drop 2), + opcodes::OP_ROT => stack_opcode!(stack(3): require 3 perm (1 -> 2 -> 3)), + opcodes::OP_SWAP => stack_opcode!(stack(2): require 3 swap (1, 2)), + opcodes::OP_TUCK => stack_opcode!(stack(2): require 2 copy 2 copy 1 drop 2), opcodes::OP_IFDUP => { - match stack.last().map(|v| read_scriptbool(v.as_slice())) { + let top_bool = { + let top = stack.peek_mut(); + top.bool_value() + }; + match top_bool { + Some(false) => { } + Some(true) => { stack_opcode!(stack(1): require 1 copy 1); } None => { let mut stack_true = stack.clone(); - stack_true.push(Slice(script_true)); - stack.push(Slice(script_false)); - return recurse(script.slice_from(index - 1), stack, depth + 1) && - recurse(script.slice_from(index - 1), stack_true, depth + 1); - } - Some(false) => {} - Some(true) => { stack_opcode_provable!(stack(1): copy 1); } - } - } - // Not clear what we can meaningfully do with these (I guess add an - // `Unknown` variant to `MaybeOwned` and change all the code to deal - // with it), and they aren't common, so just say "not unspendable". - opcodes::OP_DEPTH | opcodes::OP_SIZE => { return false; } - opcodes::OP_EQUAL | opcodes::OP_EQUALVERIFY => { - if stack.len() < 2 { - stack.pop(); - stack.pop(); - let mut stack_true = stack.clone(); - if op == opcodes::OP_EQUALVERIFY { - return recurse(script.slice_from(index), stack, depth + 1); - } else { - stack_true.push(Slice(script_true)); - stack.push(Slice(script_false)); - return recurse(script.slice_from(index), stack, depth + 1) && - recurse(script.slice_from(index), stack_true, depth + 1); + // Try pushing false and see what happens + if stack.peek_mut().set_bool_value(false).is_ok() { + match recurse(script.slice_from(index - 1), stack, depth + 1) { + Ok(res) => { return Ok(res); } + Err(_) => {} + } + } + // Failing that, push true + try!(stack_true.peek_mut().set_bool_value(true)); + return recurse(script.slice_from(index - 1), stack_true, depth + 1); } } - let a = stack.pop().unwrap(); - let b = stack.pop().unwrap(); - stack.push(Slice(if a == b { script_true } else { script_false })); - if op == opcodes::OP_EQUALVERIFY { op_verify_provable!(stack); } } - opcodes::OP_1ADD => num_opcode_provable!(stack(a): a + 1), - opcodes::OP_1SUB => num_opcode_provable!(stack(a): a - 1), - opcodes::OP_NEGATE => num_opcode_provable!(stack(a): -a), - opcodes::OP_ABS => num_opcode_provable!(stack(a): a.abs()), - opcodes::OP_NOT => num_opcode_provable!(stack(a): if a == 0 {1} else {0}), - opcodes::OP_0NOTEQUAL => num_opcode_provable!(stack(a): if a != 0 {1} else {0}), - opcodes::OP_ADD => num_opcode_provable!(stack(b, a): a + b), - opcodes::OP_SUB => num_opcode_provable!(stack(b, a): a - b), - opcodes::OP_BOOLAND => num_opcode_provable!(stack(b, a): if a != 0 && b != 0 {1} else {0}), - opcodes::OP_BOOLOR => num_opcode_provable!(stack(b, a): if a != 0 || b != 0 {1} else {0}), - opcodes::OP_NUMEQUAL => num_opcode_provable!(stack(b, a): if a == b {1} else {0}), - opcodes::OP_NUMNOTEQUAL => num_opcode_provable!(stack(b, a): if a != b {1} else {0}), + opcodes::OP_DEPTH => { + let len = stack.len() as i64; + let new_elem = stack.push_alloc(AbstractStackElem::new_unknown()); + try!(new_elem.set_numeric()); + try!(new_elem.set_num_lo(len)); + } + opcodes::OP_SIZE => { + let top = stack.peek_index(); + let new_elem = stack.push_alloc(AbstractStackElem::new_unknown()); + try!(new_elem.set_numeric()); + try!(new_elem.add_validator(Validator { args: vec![top], + check: check_op_size, + update: update_op_size })); + } + opcodes::OP_EQUAL => boolean_opcode_satisfy!(stack, binary op_equal), + opcodes::OP_EQUALVERIFY => { + boolean_opcode_satisfy!(stack, binary op_equal); + op_verify_satisfy!(stack); + } + opcodes::OP_NOT => boolean_opcode_satisfy!(stack, unary op_not), + opcodes::OP_0NOTEQUAL => boolean_opcode_satisfy!(stack, unary op_0notequal), + opcodes::OP_NUMEQUAL => boolean_opcode_satisfy!(stack, binary op_numequal), opcodes::OP_NUMEQUALVERIFY => { - num_opcode_provable!(stack(b, a): if a == b {1} else {0}); - op_verify_provable!(stack); + boolean_opcode_satisfy!(stack, binary op_numequal); + op_verify_satisfy!(stack); } - opcodes::OP_LESSTHAN => num_opcode_provable!(stack(b, a): if a < b {1} else {0}), - opcodes::OP_GREATERTHAN => num_opcode_provable!(stack(b, a): if a > b {1} else {0}), - opcodes::OP_LESSTHANOREQUAL => num_opcode_provable!(stack(b, a): if a <= b {1} else {0}), - opcodes::OP_GREATERTHANOREQUAL => num_opcode_provable!(stack(b, a): if a >= b {1} else {0}), - opcodes::OP_MIN => num_opcode_provable!(stack(b, a): if a < b {a} else {b}), - opcodes::OP_MAX => num_opcode_provable!(stack(b, a): if a > b {a} else {b}), - opcodes::OP_WITHIN => num_opcode_provable!(stack(c, b, a): if b <= a && a < c {1} else {0}), - opcodes::OP_RIPEMD160 => hash_opcode_provable!(stack, Ripemd160), - opcodes::OP_SHA1 => hash_opcode_provable!(stack, Sha1), - opcodes::OP_SHA256 => hash_opcode_provable!(stack, Sha256), - opcodes::OP_HASH160 => { - hash_opcode_provable!(stack, Sha256); - hash_opcode_provable!(stack, Ripemd160); + opcodes::OP_NUMNOTEQUAL => boolean_opcode_satisfy!(stack, binary op_numnotequal), + opcodes::OP_LESSTHAN => boolean_opcode_satisfy!(stack, binary op_numlt), + opcodes::OP_GREATERTHAN => boolean_opcode_satisfy!(stack, binary op_numgt), + opcodes::OP_LESSTHANOREQUAL => boolean_opcode_satisfy!(stack, binary op_numlteq), + opcodes::OP_GREATERTHANOREQUAL => boolean_opcode_satisfy!(stack, binary op_numgteq), + opcodes::OP_1ADD | opcodes::OP_1SUB | opcodes::OP_NEGATE | + opcodes::OP_ABS | opcodes::OP_ADD | opcodes::OP_SUB | + opcodes::OP_BOOLAND | opcodes::OP_BOOLOR | + opcodes::OP_MIN | opcodes::OP_MAX | opcodes::OP_WITHIN => { + return Err(Unanalyzable); } - opcodes::OP_HASH256 => { - hash_opcode_provable!(stack, Sha256); - hash_opcode_provable!(stack, Sha256); - } - // Ignore code separators since we won't check signatures + opcodes::OP_RIPEMD160 => unary_opcode_satisfy!(stack, op_ripemd160), + opcodes::OP_SHA1 => unary_opcode_satisfy!(stack, op_sha1), + opcodes::OP_SHA256 => unary_opcode_satisfy!(stack, op_sha256), + opcodes::OP_HASH160 => unary_opcode_satisfy!(stack, op_hash160), + opcodes::OP_HASH256 => unary_opcode_satisfy!(stack, op_hash256), + // Ignore code separators since we don't check signatures opcodes::OP_CODESEPARATOR => {} - opcodes::OP_CHECKSIG | opcodes::OP_CHECKSIGVERIFY => { - stack.pop(); - stack.pop(); - // If it's a VERIFY op, assume it passed and carry on - if op != opcodes::OP_CHECKSIGVERIFY { - let mut stack_true = stack.clone(); - stack_true.push(Slice(script_true)); - stack.push(Slice(script_false)); - return recurse(script.slice_from(index), stack, depth + 1) && - recurse(script.slice_from(index), stack_true, depth + 1); - } + opcodes::OP_CHECKSIG => boolean_opcode_satisfy!(stack, binary op_checksig), + opcodes::OP_CHECKSIGVERIFY => { + boolean_opcode_satisfy!(stack, binary op_checksig); + op_verify_satisfy!(stack); } opcodes::OP_CHECKMULTISIG | opcodes::OP_CHECKMULTISIGVERIFY => { - // Read all the keys - if stack.len() >= 1 { - let n_keys = match read_scriptint(stack.pop().unwrap().as_slice()) { - Ok(n) => n, - Err(_) => { return true; } - }; - if n_keys < 0 || n_keys > 20 { - return true; - } - for _ in range(0, n_keys) { stack.pop(); } - - // Read all the signatures - if stack.len() >= 1 { - let n_sigs = match read_scriptint(stack.pop().unwrap().as_slice()) { - Ok(n) => n, - Err(_) => { return true; } - }; - if n_sigs < 0 || n_sigs > n_keys { - return true; - } - for _ in range(0, n_sigs) { stack.pop(); } + let (n_keys, n_keys_hi) = { + let elem = stack.pop_mut(); + try!(elem.set_numeric()); + try!(elem.set_num_lo(0)); + try!(elem.set_num_hi(20)); + (elem.num_lo(), elem.num_hi()) + }; + let mut allowable_failures: i64 = 0; + for _ in range(0, n_keys) { + let key = stack.pop_mut(); + if key.may_be_pubkey() { + allowable_failures += 1; } } - - // Pop one more element off the stack to be replicate a consensus bug - stack.pop(); + if n_keys == n_keys_hi { + let (n_sigs, n_sigs_hi) = { + let elem = stack.pop_mut(); + try!(elem.set_numeric()); + try!(elem.set_num_lo(0)); + try!(elem.set_num_hi(n_keys)); + (elem.num_lo(), elem.num_hi()) + }; + allowable_failures -= n_sigs; + for _ in range(0, n_sigs) { + let sig = stack.pop_mut(); + if !sig.may_be_signature() { + allowable_failures -= 1; + } + if allowable_failures < 0 { + return Err(Unsatisfiable); + } + if n_sigs != n_sigs_hi { return Err(Unanalyzable); } + } + } else { return Err(Unanalyzable); } + // Successful multisig, push an unknown boolean + { + let result = stack.push_alloc(AbstractStackElem::new_unknown()); + try!(result.set_boolean()) + } // If it's a VERIFY op, assume it passed and carry on - if op != opcodes::OP_CHECKSIGVERIFY { - let mut stack_true = stack.clone(); - stack_true.push(Slice(script_true)); - stack.push(Slice(script_false)); - return recurse(script.slice_from(index), stack, depth + 1) && - recurse(script.slice_from(index), stack_true, depth + 1); + if op == opcodes::OP_CHECKMULTISIGVERIFY { + op_verify_satisfy!(stack); } } } @@ -1251,9 +2374,15 @@ impl Script { } } // If we finished, we are only unspendable if we have false on the stack - stack.last().is_some() && !read_scriptbool(stack.last().unwrap().as_slice()) + match stack.peek_mut().bool_value() { + None => stack.peek_mut().set_bool_value(true).map(|_| stack.build_initial_stack()), + Some(true) => Ok(stack.build_initial_stack()), + Some(false) => Err(AnalyzeAlwaysReturnsFalse) + } } - recurse(raw.as_slice(), vec![], 1) + + let &Script(ref raw) = self; + recurse(raw.as_slice(), AbstractStack::new(), 1) } } @@ -1556,6 +2685,10 @@ mod test { #[test] fn provably_unspendable_test() { + // p2pk + assert_eq!(Script(ThinVec::from_vec("410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac".from_hex().unwrap())).is_provably_unspendable(), false); + assert_eq!(Script(ThinVec::from_vec("4104ea1feff861b51fe3f5f8a3b12d0f4712db80e919548a80839fc47c6a21e66d957e9c5d8cd108c7a2d2324bad71f9904ac0ae7336507d785b17a2c115e427a32fac".from_hex().unwrap())).is_provably_unspendable(), false); + // p2pkhash assert_eq!(Script(ThinVec::from_vec("76a914ee61d57ab51b9d212335b1dba62794ac20d2bcf988ac".from_hex().unwrap())).is_provably_unspendable(), false); assert_eq!(Script(ThinVec::from_vec("6aa9149eb21980dc9d413d8eac27314938b9da920ee53e87".from_hex().unwrap())).is_provably_unspendable(), true); // if return; else return @@ -1576,9 +2709,17 @@ mod test { assert_eq!(Script(ThinVec::from_vec("5173".from_hex().unwrap())).is_provably_unspendable(), false); assert_eq!(Script(ThinVec::from_vec("0073".from_hex().unwrap())).is_provably_unspendable(), true); // this is honest to god tx e411dbebd2f7d64dafeef9b14b5c59ec60c36779d43f850e5e347abee1e1a455 on mainnet - assert_eq!(Script(ThinVec::from_vec("76a9144838a081d73cf134e8ff9cfd4015406c73beceb388acacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacac".from_hex().unwrap())).is_provably_unspendable(), false); - // This one is real and spent + assert_eq!(Script(ThinVec::from_vec("76a9144838a081d73cf134e8ff9cfd4015406c73beceb388acacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacac".from_hex().unwrap())).is_provably_unspendable(), true); + // Real, testnet spent ones that caused me trouble assert_eq!(Script(ThinVec::from_vec("7c51880087".from_hex().unwrap())).is_provably_unspendable(), false); + assert_eq!(Script(ThinVec::from_vec("9e91".from_hex().unwrap())).is_provably_unspendable(), false); + assert_eq!(Script(ThinVec::from_vec("76a97ca8a687".from_hex().unwrap())).is_provably_unspendable(), false); + assert_eq!(Script(ThinVec::from_vec("04010203047576a914bfbd43270c1e824c01e27386844d062d2f7518a688ad76a97614d2f7b8a37fb9b46782534078f9748f41d61a22f3877c148d4c6a901a3d87ed680478931dc9b6f0871af0ab879b69ac".from_hex().unwrap())).is_provably_unspendable(), false); + assert_eq!(Script(ThinVec::from_vec("03800000".from_hex().unwrap())).is_provably_unspendable(), false); + // This one is cool -- a 2-of-4 multisig with four pks given, only two of which are legit + assert_eq!(Script(ThinVec::from_vec("522103bb52138972c48a132fc1f637858c5189607dd0f7fe40c4f20f6ad65f2d389ba42103bb52138972c48a132fc1f637858c5189607dd0f7fe40c4f20f6ad65f2d389ba45f6054ae".from_hex().unwrap())).is_provably_unspendable(), false); + // This one is on mainnet oeO + assert_eq!(Script(ThinVec::from_vec("827651a0698faaa9a8a7a687".from_hex().unwrap())).is_provably_unspendable(), false); } } diff --git a/src/internal_macros.rs b/src/internal_macros.rs index 22cff6f..d6e2b3a 100644 --- a/src/internal_macros.rs +++ b/src/internal_macros.rs @@ -156,7 +156,11 @@ macro_rules! impl_array_newtype( $thing::from_slice(self.as_slice()) } } + } +) +macro_rules! impl_array_newtype_show( + ($thing:ident) => { impl ::std::fmt::Show for $thing { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { write!(f, concat!(stringify!($thing), "({})"), self.as_slice()) diff --git a/src/lib.rs b/src/lib.rs index e083120..b4e82bd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,6 +33,9 @@ #![feature(overloaded_calls)] #![feature(unsafe_destructor)] #![feature(default_type_params)] +#![feature(struct_variant)] +#![feature(unboxed_closure_sugar)] +#![feature(unboxed_closures)] #![comment = "Rust Bitcoin Library"] #![license = "CC0"] diff --git a/src/util/hash.rs b/src/util/hash.rs index af9c111..84c95ef 100644 --- a/src/util/hash.rs +++ b/src/util/hash.rs @@ -36,6 +36,12 @@ use util::uint::Uint256; pub struct Sha256dHash([u8, ..32]); impl_array_newtype!(Sha256dHash, u8, 32) +impl ::std::fmt::Show for Sha256dHash { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "{}", self.be_hex_string().as_slice()) + } +} + /// A RIPEMD-160 hash pub struct Ripemd160Hash([u8, ..20]); diff --git a/src/wallet/bip32.rs b/src/wallet/bip32.rs index 6df4ac4..affd5ac 100644 --- a/src/wallet/bip32.rs +++ b/src/wallet/bip32.rs @@ -36,10 +36,12 @@ use util::base58::{Base58Error, /// A chain code pub struct ChainCode([u8, ..32]); impl_array_newtype!(ChainCode, u8, 32) +impl_array_newtype_show!(ChainCode) /// A fingerprint pub struct Fingerprint([u8, ..4]); impl_array_newtype!(Fingerprint, u8, 4) +impl_array_newtype_show!(Fingerprint) impl Default for Fingerprint { fn default() -> Fingerprint { Fingerprint([0, 0, 0, 0]) }