// Rust Bitcoin Library // Written in 2014 by // Andrew Poelstra // // To the extent possible under law, the author(s) have dedicated all // copyright and related and neighboring rights to this software to // the public domain worldwide. This software is distributed without // any warranty. // // You should have received a copy of the CC0 Public Domain Dedication // along with this software. // If not, see . // //! # Script //! //! Scripts define Bitcoin's digital signature scheme: a signature is formed //! from a script (the second half of which is defined by a coin to be spent, //! and the first half provided by the spending transaction), and is valid //! iff the script leaves `TRUE` on the stack after being evaluated. //! Bitcoin's script is a stack-based assembly language similar in spirit to //! Forth. //! //! This module provides the structures and functions needed to support scripts. //! use std::hash; use std::char::from_digit; use std::default::Default; use std::{fmt, ops}; use serialize::hex::ToHex; use crypto::digest::Digest; use crypto::ripemd160::Ripemd160; use crypto::sha1::Sha1; use crypto::sha2::Sha256; use secp256k1::{self, Secp256k1}; use secp256k1::key::PublicKey; use serde; use blockdata::opcodes; use blockdata::transaction::{Transaction, TxIn}; use network::encodable::{ConsensusDecodable, ConsensusEncodable}; use network::serialize::{SimpleDecoder, SimpleEncoder, serialize}; use util::hash::Sha256dHash; use util::misc::script_find_and_remove; #[derive(PartialEq, Eq, Debug)] /// A Bitcoin script pub struct Script(Box<[u8]>); impl Clone for Script { fn clone(&self) -> Script { Script(self.0.to_vec().into_boxed_slice()) } } impl fmt::LowerHex for Script { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { for &ch in self.0.iter() { try!(write!(f, "{:02x}", ch)); } Ok(()) } } impl fmt::UpperHex for Script { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { for &ch in self.0.iter() { try!(write!(f, "{:02X}", ch)); } Ok(()) } } #[derive(PartialEq, Eq, Debug, Clone)] /// An object which can be used to construct a script piece by piece pub struct Builder(Vec); display_from_debug!(Builder); impl hash::Hash for Script { #[inline] fn hash(&self, state: &mut H) where H: hash::Hasher { (&self.0[..]).hash(state); } #[inline] fn hash_slice(data: &[Script], state: &mut H) where H: hash::Hasher { for s in data.iter() { (&s.0[..]).hash(state); } } } /// Ways that a script might fail. Not everything is split up as /// much as it could be; patches welcome if more detailed errors /// would help you. #[derive(PartialEq, Eq, Debug, Clone)] pub enum Error { /// 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 BadSignature, /// An ECDSA error Ecdsa(secp256k1::Error), /// An OP_ELSE happened while not in an OP_IF tree ElseWithoutIf, /// An OP_ENDIF happened while not in an OP_IF tree EndifWithoutIf, /// An OP_EQUALVERIFY failed (expected, gotten) EqualVerifyFailed(String, String), /// An OP_IF happened with an empty stack 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 ExecutedReturn, /// A multisig tx with negative or too many keys MultisigBadKeyCount(isize), /// A multisig tx with negative or too many signatures MultisigBadSigCount(isize), /// Used OP_PICK with a negative index NegativePick, /// Used OP_ROLL with a negative index NegativeRoll, /// Tried to execute a signature operation but no transaction context was provided NoTransaction, /// An OP_NUMEQUALVERIFY failed (expected, gotten) NumEqualVerifyFailed(i64, i64), /// Tried to read an array off the stack as a number when it was more than 4 bytes 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, } display_from_debug!(Error); /// 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, &[usize]) -> 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, &[usize]) -> Result<(), Error> } impl Clone for Validator { fn clone(&self) -> Validator { Validator { args: self.args.clone(), check: self.check, update: self.update } } } // Validators mod check { use super::AbstractStackElem; pub fn op_size(elem: &AbstractStackElem, others: &[usize]) -> bool { let other = unsafe { elem.lookup(others[0]) }; elem.num_hi() >= other.len_lo() as i64 && elem.num_lo() <= other.len_hi() as i64 } pub fn op_equal(elem: &AbstractStackElem, others: &[usize]) -> 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()) } } } pub fn op_not(elem: &AbstractStackElem, others: &[usize]) -> 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 } } pub fn op_0notequal(elem: &AbstractStackElem, others: &[usize]) -> 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 } } pub fn op_numequal(elem: &AbstractStackElem, others: &[usize]) -> 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()) } } } pub fn op_numnotequal(elem: &AbstractStackElem, others: &[usize]) -> 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) } } pub fn op_numlt(elem: &AbstractStackElem, others: &[usize]) -> 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), } } pub fn op_numgt(elem: &AbstractStackElem, others: &[usize]) -> 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) } } pub fn op_numlteq(elem: &AbstractStackElem, others: &[usize]) -> 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) } } pub fn op_numgteq(elem: &AbstractStackElem, others: &[usize]) -> 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) } } pub fn op_ripemd160(elem: &AbstractStackElem, _: &[usize]) -> bool { elem.may_be_hash160() } pub fn op_sha1(elem: &AbstractStackElem, _: &[usize]) -> bool { elem.may_be_hash160() } pub fn op_hash160(elem: &AbstractStackElem, _: &[usize]) -> bool { elem.may_be_hash160() } pub fn op_sha256(elem: &AbstractStackElem, _: &[usize]) -> bool { elem.may_be_hash256() } pub fn op_hash256(elem: &AbstractStackElem, _: &[usize]) -> bool { elem.may_be_hash256() } pub fn op_checksig(elem: &AbstractStackElem, others: &[usize]) -> 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() } } } mod update { use super::{AbstractStackElem, Error}; use crypto::digest::Digest; use crypto::ripemd160::Ripemd160; use crypto::sha1::Sha1; use crypto::sha2::Sha256; pub fn op_size(elem: &mut AbstractStackElem, others: &[usize]) -> Result<(), Error> { 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 boolean(elem: &mut AbstractStackElem) -> Result<(), Error> { // 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(Error::AnalyzeNeitherBoolWorks), (true, false) => elem.set_bool_value(true), (false, true) => elem.set_bool_value(false) } } pub fn op_equal(elem: &mut AbstractStackElem, others: &[usize]) -> Result<(), Error> { match elem.bool_value() { None => 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(Error::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(Error::Unsatisfiable); } } // Equalize full values match (one.raw_value().map(|r| r.to_vec()), two.raw_value().map(|r| r.to_vec())) { (None, None) => {}, (None, Some(x)) => try!(one.set_value(&x)), (Some(x), None) => try!(two.set_value(&x)), (Some(x), Some(y)) => { if x != y { return Err(Error::Unsatisfiable); } } } Ok(()) } } } pub fn op_not(elem: &mut AbstractStackElem, others: &[usize]) -> Result<(), Error> { match elem.bool_value() { None => 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(Error::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(Error::Unsatisfiable), Some(false) => Ok(()) } } } } pub fn op_0notequal(elem: &mut AbstractStackElem, others: &[usize]) -> Result<(), Error> { match elem.bool_value() { None => 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(Error::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(Error::Unsatisfiable) } } } } pub fn op_numequal(elem: &mut AbstractStackElem, others: &[usize]) -> Result<(), Error> { match elem.bool_value() { None => 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()) } } } pub fn op_numnotequal(elem: &mut AbstractStackElem, others: &[usize]) -> Result<(), Error> { match elem.bool_value() { None => 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(()) } } } pub fn op_numlt(elem: &mut AbstractStackElem, others: &[usize]) -> Result<(), Error> { match elem.bool_value() { None => 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()) } } } pub fn op_numgt(elem: &mut AbstractStackElem, others: &[usize]) -> Result<(), Error> { match elem.bool_value() { None => try!(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(()) } pub fn op_numlteq(elem: &mut AbstractStackElem, others: &[usize]) -> Result<(), Error> { match elem.bool_value() { None => try!(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(()) } pub fn op_numgteq(elem: &mut AbstractStackElem, others: &[usize]) -> Result<(), Error> { match elem.bool_value() { None => try!(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(()) } pub fn op_ripemd160(elem: &mut AbstractStackElem, others: &[usize]) -> Result<(), Error> { 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(&mut out); Some(out) } }; match hash { None => Ok(()), Some(x) => elem.set_value(&x) } } pub fn op_sha1(elem: &mut AbstractStackElem, others: &[usize]) -> Result<(), Error> { 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(&mut out); Some(out) } }; match hash { None => Ok(()), Some(x) => elem.set_value(&x) } } pub fn op_hash160(elem: &mut AbstractStackElem, others: &[usize]) -> Result<(), Error> { 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(&mut out1); let mut engine = Ripemd160::new(); engine.input(&out1); engine.result(&mut out2); Some(out2) } }; match hash { None => Ok(()), Some(x) => elem.set_value(&x) } } pub fn op_sha256(elem: &mut AbstractStackElem, others: &[usize]) -> Result<(), Error> { 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(&mut out); Some(out) } }; match hash { None => Ok(()), Some(x) => elem.set_value(&x) } } pub fn op_hash256(elem: &mut AbstractStackElem, others: &[usize]) -> Result<(), Error> { 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(&mut out); let mut engine = Sha256::new(); engine.input(&out); engine.result(&mut out); Some(out) } }; match hash { None => Ok(()), Some(x) => elem.set_value(&x) } } pub fn op_checksig(elem: &mut AbstractStackElem, others: &[usize]) -> Result<(), Error> { match elem.bool_value() { None => 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 #[derive(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: usize, /// Length upper bound len_hi: usize, /// 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(data.to_vec()), 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: usize) -> &'a AbstractStackElem { let mypos = self as *const _; let myidx = self.alloc_index.unwrap() as isize; &*mypos.offset(idx as isize - myidx) } /// Looks up another stack item by index unsafe fn lookup_mut<'a>(&'a self, idx: usize) -> &'a mut AbstractStackElem { let mypos = self as *const _ as *mut _; let myidx = self.alloc_index.unwrap() as isize; &mut *mypos.offset(idx as isize - 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[..]) } /// 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) -> usize { 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) -> usize { 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<(), Error> { // Check that this node is consistent before doing any propagation if !self.validate() { return Err(Error::AnalyzeValidateFailed); } let validators = self.validators.clone(); for v in validators.iter().cloned() { try!((v.update)(self, &v.args)); } 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)) } /// Sets the boolean value pub fn set_bool_value(&mut self, val: bool) -> Result<(), Error> { match self.bool_val { Some(x) => { if x != val { return Err(Error::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<(), Error> { 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<(), Error> { match self.raw_value().map(|x| x.to_vec()) { Some(x) => { if &x[..] == val { Ok(()) } else { Err(Error::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(val.to_vec()); Ok(()) } } } /// Sets a number to be numerically parseable pub fn set_numeric(&mut self) -> Result<(), Error> { 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 { let s = Secp256k1::with_caps(secp256k1::ContextFlag::None); ((self.len_lo() <= 33 && self.len_hi() >= 33) || (self.len_lo() <= 65 && self.len_hi() >= 65)) && (self.raw_value().is_none() || PublicKey::from_slice(&s, 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() } /// 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()) } /// 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() } /// 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()) } /// 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<(), Error> { 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<(), Error> { 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<(), Error> { 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: usize) -> Result<(), Error> { 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: usize) -> Result<(), Error> { 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<(), Error> { self.validators.push(cond); self.update() } } /// The stack used by the script satisfier #[derive(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) -> usize { 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.insert(0, idx); self.stack.insert(0, idx); } /// Construct the initial stack in the end pub fn build_initial_stack(&self) -> Vec { let res: Vec = self.initial_stack.iter().map(|&i| self.alloc[i].clone()).collect(); res } /// Increase the stack size to `n`, adding elements to the initial /// stack as necessary pub fn require_n_elems(&mut self, n: usize) { while self.stack.len() < n { self.push_initial(AbstractStackElem::new_unknown()); } } /// Push a copy of an existing element by index pub fn push(&mut self, elem: usize) { 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); &mut self.alloc[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()); } &mut self.alloc[*self.stack.last().unwrap()] } /// Obtain a stackref to the current top element pub fn peek_index(&mut self) -> usize { if self.stack.len() == 0 { self.push_initial(AbstractStackElem::new_unknown()); } *self.stack.last().unwrap() } /// Drop the top stack item fn pop(&mut self) -> usize { 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()); } &mut self.alloc[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<(), Error> { match self.alt_stack.pop() { Some(x) => { self.stack.push(x); Ok(()) } None => Err(Error::PopEmptyStack) } } /// Length of the current stack fn len(&self) -> usize { self.stack.len() } /// Delete an element from the middle of the current stack fn remove(&mut self, idx: usize) { self.stack.remove(idx); } } impl ops::Index for AbstractStack { type Output = usize; #[inline] fn index(&self, index: usize) -> &usize { &self.stack[index] } } impl ops::Index> for AbstractStack { type Output = [usize]; #[inline] fn index(&self, index: ops::Range) -> &[usize] { &self.stack[index] } } impl ops::Index> for AbstractStack { type Output = [usize]; #[inline] fn index(&self, index: ops::RangeTo) -> &[usize] { &self.stack[index] } } impl ops::Index> for AbstractStack { type Output = [usize]; #[inline] fn index(&self, index: ops::RangeFrom) -> &[usize] { &self.stack[index] } } impl ops::Index for AbstractStack { type Output = [usize]; #[inline] fn index(&self, _: ops::RangeFull) -> &[usize] { &self.stack[..] } } impl ops::IndexMut for AbstractStack { #[inline] fn index_mut(&mut self, index: usize) -> &mut usize { &mut self.stack[index] } } impl ops::IndexMut> for AbstractStack { #[inline] fn index_mut(&mut self, index: ops::Range) -> &mut [usize] { &mut self.stack[index] } } impl ops::IndexMut> for AbstractStack { #[inline] fn index_mut(&mut self, index: ops::RangeTo) -> &mut [usize] { &mut self.stack[index] } } impl ops::IndexMut> for AbstractStack { #[inline] fn index_mut(&mut self, index: ops::RangeFrom) -> &mut [usize] { &mut self.stack[index] } } impl ops::IndexMut for AbstractStack { #[inline] fn index_mut(&mut self, _: ops::RangeFull) -> &mut [usize] { &mut self.stack[..] } } impl serde::Serialize for Error { fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: serde::Serializer { serializer.visit_str(&self.to_string()) } } /// A single iteration of a script execution #[derive(PartialEq, Eq, Debug, Clone)] pub struct TraceIteration { index: usize, op_count: usize, opcode: opcodes::All, executed: bool, errored: bool, effect: opcodes::Class, stack: Vec } /// A full trace of a script execution #[derive(PartialEq, Eq, Debug, 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, /// A list of iterations pub iterations: Vec, /// An error if one was returned, or None pub error: Option } /// Hashtype of a transaction, encoded in the last byte of a signature, /// specifically in the last 5 bits `byte & 31` #[derive(PartialEq, Eq, Debug, Clone)] pub enum SigHashType { /// 0x1: Sign all outputs All, /// 0x2: Sign no outputs --- anyone can choose the destination None, /// 0x3: Sign the output whose index matches this input's index. If none exists, /// sign the hash `0000000000000000000000000000000000000000000000000000000000000001`. /// (This rule is probably an unintentional C++ism, but it's consensus so we have /// to follow it.) Single, /// ???: Anything else is a non-canonical synonym for SigHashAll, for example /// zero appears a few times in the chain Unknown } impl SigHashType { /// Returns a SigHashType along with a boolean indicating whether /// the `ANYONECANPAY` flag is set, read from the last byte of a signature. fn from_signature(signature: &[u8]) -> (SigHashType, bool) { let byte = signature[signature.len() - 1]; let sighash = match byte & 0x1f { 1 => SigHashType::All, 2 => SigHashType::None, 3 => SigHashType::Single, _ => SigHashType::Unknown }; (sighash, (byte & 0x80) != 0) } } /// A structure that can hold either a slice or vector, as necessary #[derive(Clone, Debug)] pub enum MaybeOwned<'a> { /// Freshly llocated memory Owned(Vec), /// Pointer into the original script Borrowed(&'a [u8]) } impl<'a> PartialEq for MaybeOwned<'a> { #[inline] fn eq(&self, other: &MaybeOwned) -> bool { &self[..] == &other[..] } } impl<'a> Eq for MaybeOwned<'a> {} impl<'a> ops::Index for MaybeOwned<'a> { type Output = u8; #[inline] fn index(&self, index: usize) -> &u8 { match *self { MaybeOwned::Owned(ref v) => &v[index], MaybeOwned::Borrowed(ref s) => &s[index] } } } impl<'a> ops::Index> for MaybeOwned<'a> { type Output = [u8]; #[inline] fn index(&self, index: ops::Range) -> &[u8] { match *self { MaybeOwned::Owned(ref v) => &v[index], MaybeOwned::Borrowed(ref s) => &s[index] } } } impl<'a> ops::Index> for MaybeOwned<'a> { type Output = [u8]; #[inline] fn index(&self, index: ops::RangeTo) -> &[u8] { match *self { MaybeOwned::Owned(ref v) => &v[index], MaybeOwned::Borrowed(ref s) => &s[index] } } } impl<'a> ops::Index> for MaybeOwned<'a> { type Output = [u8]; #[inline] fn index(&self, index: ops::RangeFrom) -> &[u8] { match *self { MaybeOwned::Owned(ref v) => &v[index], MaybeOwned::Borrowed(ref s) => &s[index] } } } impl<'a> ops::Index for MaybeOwned<'a> { type Output = [u8]; #[inline] fn index(&self, _: ops::RangeFull) -> &[u8] { match *self { MaybeOwned::Owned(ref v) => &v[..], MaybeOwned::Borrowed(ref s) => &s[..] } } } impl<'a> MaybeOwned<'a> { /// The number of bytes stored in the vector #[inline] fn len(&self) -> usize { match *self { MaybeOwned::Owned(ref v) => v.len(), MaybeOwned::Borrowed(ref s) => s.len() } } } 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 { if n == 0 { return vec![] } let neg = n < 0; let mut abs = if neg { -n } else { n } as usize; let mut v = vec![]; while abs > 0xFF { v.push((abs & 0xFF) as u8); abs >>= 8; } // If the number's value causes the sign bit to be set, we need an extra // byte to get the correct value and correct sign bit if abs & 0x80 != 0 { v.push(abs as u8); v.push(if neg { 0x80u8 } else { 0u8 }); } // Otherwise we just set the sign bit ourselves else { abs |= if neg { 0x80 } else { 0 }; v.push(abs as u8); } v } /// Helper to decode an integer in script format /// Notice that this fails on overflow: the result is the same as in /// bitcoind, that only 4-byte signed-magnitude values may be read as /// numbers. They can be added or subtracted (and a long time ago, /// multiplied and divided), and this may result in numbers which /// can't be written out in 4 bytes or less. This is ok! The number /// just can't be read as a number again. /// This is a bit crazy and subtle, but it makes sense: you can load /// 32-bit numbers and do anything with them, which back when mult/div /// was allowed, could result in up to a 64-bit number. We don't want /// overflow since that's suprising --- and we don't want numbers that /// don't fit in 64 bits (for efficiency on modern processors) so we /// simply say, anything in excess of 32 bits is no longer a number. /// This is basically a ranged type implementation. pub fn read_scriptint(v: &[u8]) -> Result { let len = v.len(); if len == 0 { return Ok(0); } if len > 4 { return Err(Error::NumericOverflow); } let (mut ret, sh) = v.iter() .fold((0, 0), |(acc, sh), n| (acc + ((*n as i64) << sh), sh + 8)); if v[len - 1] & 0x80 != 0 { ret &= (1 << sh - 1) - 1; ret = -ret; } Ok(ret) } /// This is like "read_scriptint then map 0 to false and everything /// else as true", except that the overflow rules don't apply. #[inline] pub fn read_scriptbool(v: &[u8]) -> bool { !(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 pub fn read_uint(data: &[u8], size: usize) -> Result { if data.len() < size { Err(Error::EarlyEndOfScript) } else { let mut ret = 0; for i in 0..size { ret += (data[i] as usize) << (i * 8); } Ok(ret) } } /// Check a signature -- returns an error that is currently just translated /// into a 0/1 to push onto the script stack fn check_signature(secp: &Secp256k1, sig_slice: &[u8], pk_slice: &[u8], script: Vec, tx: &Transaction, input_index: usize) -> Result<(), Error> { // Check public key let pubkey = PublicKey::from_slice(secp, pk_slice); if pubkey.is_err() { return Err(Error::BadPublicKey); } let pubkey = pubkey.unwrap(); // Check signature and hashtype if sig_slice.len() == 0 { return Err(Error::BadSignature); } let (hashtype, anyone_can_pay) = SigHashType::from_signature(sig_slice); // Compute the transaction data to be hashed let mut tx_copy = Transaction { version: tx.version, lock_time: tx.lock_time, input: Vec::with_capacity(tx.input.len()), output: tx.output.clone() }; // Put the script into an Option so that we can move it (via take_unwrap()) // in the following branch/loop without the move-checker complaining about // multiple moves. let mut script = Some(script); if anyone_can_pay { // 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(script.take().unwrap().into_boxed_slice()); tx_copy.input = vec![old_input]; } else { // Otherwise we keep all the inputs, blanking out the others and even // resetting their sequence no. if appropriate for (n, input) in tx.input.iter().enumerate() { // Zero out the scripts of other inputs let mut new_input = TxIn { prev_hash: input.prev_hash, prev_index: input.prev_index, sequence: input.sequence, script_sig: Script::new() }; if n == input_index { new_input.script_sig = Script(script.take().unwrap().into_boxed_slice()); } else { new_input.script_sig = Script::new(); // If we aren't signing them, also zero out the sequence number if hashtype == SigHashType::Single || hashtype == SigHashType::None { new_input.sequence = 0; } } tx_copy.input.push(new_input); } } // Erase outputs as appropriate let mut sighash_single_bug = false; match hashtype { SigHashType::None => { tx_copy.output = vec![]; } SigHashType::Single => { if input_index < tx_copy.output.len() { let mut new_outs = Vec::with_capacity(input_index + 1); for _ in 0..input_index { new_outs.push(Default::default()) } new_outs.push(tx_copy.output.swap_remove(input_index)); tx_copy.output = new_outs; } else { sighash_single_bug = true; } } SigHashType::All | SigHashType::Unknown => {} } let signature_hash = if sighash_single_bug { vec![1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] } else { let mut data_to_sign = serialize(&tx_copy).unwrap(); data_to_sign.push(*sig_slice.last().unwrap()); data_to_sign.push(0); data_to_sign.push(0); data_to_sign.push(0); serialize(&Sha256dHash::from_data(&data_to_sign[..])).unwrap() }; // We can unwrap -- only failure mode is on length, which is fixed to 32 let msg = secp256k1::Message::from_slice(&signature_hash[..]).unwrap(); let sig = try!(secp256k1::Signature::from_der(secp, sig_slice).map_err(Error::Ecdsa)); Secp256k1::verify(secp, &msg, &sig, &pubkey).map_err(Error::Ecdsa) } // Macro to translate English stack instructions into Rust code. // All number are references to stack positions: 1 is the top, // 2 is the second-to-top, etc. The numbers do not change within // an opcode; to delete the top two items do `drop 1 drop 2` // rather than `drop 1 drop 1`, which will fail. // This is useful for only about a dozen opcodes, but those ones // were really hard to read and verify -- see OP_PICK and OP_ROLL // for an example of what Rust vector-stack manipulation looks // 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(Error::PopEmptyStack); } // Do copies $( let elem = $stack[top - $c].clone(); $stack.push(elem); )* // Do swaps $( (&mut $stack[..]).swap(top - $a, top - $b); )* // Do permutations $( let first = $first; $( (&mut $stack[..]).swap(top - first, top - $i); )* )* // Do drops last so that dropped values will be available above $( $stack.remove(top - $d); )* }); } /// Macro to translate numerical operations into stack ones macro_rules! num_opcode { ($stack:ident($($var:ident),*): $op:expr) => ({ $( let $var = try!(read_scriptint(&match $stack.pop() { Some(elem) => elem, None => { return Err(Error::PopEmptyStack); } }[..])); )* $stack.push(MaybeOwned::Owned(build_scriptint($op))); // Return a tuple of all the variables ($( $var ),*) }); } 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: check::$op, update: 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: check::$op, update: 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: check::$op, update: 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: check::$op, update: update::$op })); }); } /// Macro to translate hashing operations into stack ones macro_rules! hash_opcode { ($stack:ident, $hash:ident) => ({ match $stack.pop() { None => { return Err(Error::PopEmptyStack); } Some(v) => { let mut engine = $hash::new(); engine.input(&v[..]); 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(&mut ret); $stack.push(MaybeOwned::Owned(ret)); } } }); } // OP_VERIFY macro macro_rules! op_verify { ($stack:expr, $err:expr) => ( match $stack.last().map(|v| read_scriptbool(&v[..])) { None => { return Err(Error::VerifyEmptyStack); } Some(false) => { return Err($err); } Some(true) => { $stack.pop(); } } ) } macro_rules! op_verify_satisfy { ($stack:expr) => ({ try!($stack.peek_mut().set_bool_value(true)); $stack.pop(); }) } impl Script { /// Creates a new empty script pub fn new() -> Script { Script(vec![].into_boxed_slice()) } /// The length in bytes of the script pub fn len(&self) -> usize { self.0.len() } /// Trace a script pub fn trace<'a>(&'a self, secp: &Secp256k1, stack: &mut Vec>, input_context: Option<(&Transaction, usize)>) -> ScriptTrace { let mut trace = ScriptTrace { script: self.clone(), initial_stack: stack.iter().map(|elem| (&elem[..]).to_hex()).collect(), iterations: vec![], error: None }; match self.evaluate(secp, stack, input_context, Some(&mut trace.iterations)) { Ok(_) => {}, Err(e) => { trace.error = Some(e.clone()); } } trace } /// Evaluate the script, modifying the stack in place pub fn evaluate<'a>(&'a self, secp: &Secp256k1, stack: &mut Vec>, input_context: Option<(&Transaction, usize)>, mut trace: Option<&mut Vec>) -> Result<(), Error> { let mut codeseparator_index = 0; let mut exec_stack = vec![]; let mut alt_stack = vec![]; let mut index = 0; let mut op_count = 0; while index < self.0.len() { let executing = exec_stack.iter().all(|e| *e); let byte = self.0[index]; // Write out the trace, except the stack which we don't know yet match trace { Some(ref mut t) => { let opcode = opcodes::All::from(byte); t.push(TraceIteration { index: index, opcode: opcode, executed: executing, errored: true, op_count: op_count, effect: opcode.classify(), stack: vec!["".to_string()] }); } None => {} } op_count += 1; index += 1; // The definitions of all these categories are in opcodes.rs match (executing, opcodes::All::from(byte).classify()) { // Illegal operations mean failure regardless of execution state (_, opcodes::Class::IllegalOp) => return Err(Error::IllegalOpcode), // Push number (true, opcodes::Class::PushNum(n)) => stack.push(MaybeOwned::Owned(build_scriptint(n as i64))), // Return operations mean failure, but only if executed (true, opcodes::Class::ReturnOp) => return Err(Error::ExecutedReturn), // Data-reading statements still need to read, even when not executing (_, opcodes::Class::PushBytes(n)) => { let n = n as usize; if self.0.len() < index + n { return Err(Error::EarlyEndOfScript); } if executing { stack.push(MaybeOwned::Borrowed(&self.0[index..index + n])); } index += n; } (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA1)) => { if self.0.len() < index + 1 { return Err(Error::EarlyEndOfScript); } let n = try!(read_uint(&self.0[index..], 1)); if self.0.len() < index + 1 + n { return Err(Error::EarlyEndOfScript); } if executing { stack.push(MaybeOwned::Borrowed(&self.0[index + 1..index + n + 1])); } index += 1 + n; } (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA2)) => { if self.0.len() < index + 2 { return Err(Error::EarlyEndOfScript); } let n = try!(read_uint(&self.0[index..], 2)); if self.0.len() < index + 2 + n { return Err(Error::EarlyEndOfScript); } if executing { stack.push(MaybeOwned::Borrowed(&self.0[index + 2..index + n + 2])); } index += 2 + n; } (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4)) => { if self.0.len() < index + 4 { return Err(Error::EarlyEndOfScript); } let n = try!(read_uint(&self.0[index..], 4)); if self.0.len() < index + 4 + n { return Err(Error::EarlyEndOfScript); } if executing { stack.push(MaybeOwned::Borrowed(&self.0[index + 4..index + n + 4])); } index += 4 + n; } // If-statements take effect when not executing (false, opcodes::Class::Ordinary(opcodes::Ordinary::OP_IF)) => exec_stack.push(false), (false, opcodes::Class::Ordinary(opcodes::Ordinary::OP_NOTIF)) => exec_stack.push(false), (false, opcodes::Class::Ordinary(opcodes::Ordinary::OP_ELSE)) => { match exec_stack.last_mut() { Some(ref_e) => { *ref_e = !*ref_e } None => { return Err(Error::ElseWithoutIf); } } } (false, opcodes::Class::Ordinary(opcodes::Ordinary::OP_ENDIF)) => { if exec_stack.pop().is_none() { return Err(Error::EndifWithoutIf); } } // No-ops and non-executed operations do nothing (true, opcodes::Class::NoOp) | (false, _) => {} // Actual opcodes (true, opcodes::Class::Ordinary(op)) => { match op { opcodes::Ordinary::OP_PUSHDATA1 | opcodes::Ordinary::OP_PUSHDATA2 | opcodes::Ordinary::OP_PUSHDATA4 => { // handled above } opcodes::Ordinary::OP_IF => { match stack.pop().map(|v| read_scriptbool(&v[..])) { None => { return Err(Error::IfEmptyStack); } Some(b) => exec_stack.push(b) } } opcodes::Ordinary::OP_NOTIF => { match stack.pop().map(|v| read_scriptbool(&v[..])) { None => { return Err(Error::IfEmptyStack); } Some(b) => exec_stack.push(!b), } } opcodes::Ordinary::OP_ELSE => { match exec_stack.last_mut() { Some(ref_e) => { *ref_e = !*ref_e } None => { return Err(Error::ElseWithoutIf); } } } opcodes::Ordinary::OP_ENDIF => { if exec_stack.pop().is_none() { return Err(Error::EndifWithoutIf); } } opcodes::Ordinary::OP_VERIFY => op_verify!(stack, Error::VerifyFailed), opcodes::Ordinary::OP_TOALTSTACK => { match stack.pop() { None => { return Err(Error::PopEmptyStack); } Some(elem) => { alt_stack.push(elem); } } } opcodes::Ordinary::OP_FROMALTSTACK => { match alt_stack.pop() { None => { return Err(Error::PopEmptyStack); } Some(elem) => { stack.push(elem); } } } opcodes::Ordinary::OP_2DROP => stack_opcode!(stack(2): drop 1; drop 2), opcodes::Ordinary::OP_2DUP => stack_opcode!(stack(2): copy 2; copy 1), opcodes::Ordinary::OP_3DUP => stack_opcode!(stack(3): copy 3; copy 2; copy 1), opcodes::Ordinary::OP_2OVER => stack_opcode!(stack(4): copy 4; copy 3), opcodes::Ordinary::OP_2ROT => stack_opcode!(stack(6): perm (1, 3, 5); perm (2, 4, 6)), opcodes::Ordinary::OP_2SWAP => stack_opcode!(stack(4): swap (2, 4); swap (1, 3)), opcodes::Ordinary::OP_DROP => stack_opcode!(stack(1): drop 1), opcodes::Ordinary::OP_DUP => stack_opcode!(stack(1): copy 1), opcodes::Ordinary::OP_NIP => stack_opcode!(stack(2): drop 2), opcodes::Ordinary::OP_OVER => stack_opcode!(stack(2): copy 2), opcodes::Ordinary::OP_PICK => { let n = match stack.pop() { Some(data) => try!(read_scriptint(&data[..])), None => { return Err(Error::PopEmptyStack); } }; if n < 0 { return Err(Error::NegativePick); } let n = n as usize; stack_opcode!(stack(n + 1): copy n + 1) } opcodes::Ordinary::OP_ROLL => { let n = match stack.pop() { Some(data) => try!(read_scriptint(&data[..])), None => { return Err(Error::PopEmptyStack); } }; if n < 0 { return Err(Error::NegativeRoll); } let n = n as usize; stack_opcode!(stack(n + 1): copy n + 1 drop n + 1) } opcodes::Ordinary::OP_ROT => stack_opcode!(stack(3): perm (1, 2, 3)), opcodes::Ordinary::OP_SWAP => stack_opcode!(stack(2): swap (1, 2)), opcodes::Ordinary::OP_TUCK => stack_opcode!(stack(2): copy 2; copy 1 drop 2), opcodes::Ordinary::OP_IFDUP => { match stack.last().map(|v| read_scriptbool(&v[..])) { None => { return Err(Error::IfEmptyStack); } Some(false) => {} Some(true) => { stack_opcode!(stack(1): copy 1); } } } opcodes::Ordinary::OP_DEPTH => { let len = stack.len() as i64; stack.push(MaybeOwned::Owned(build_scriptint(len))); } opcodes::Ordinary::OP_SIZE => { match stack.last().map(|v| v.len() as i64) { None => { return Err(Error::IfEmptyStack); } Some(n) => { stack.push(MaybeOwned::Owned(build_scriptint(n))); } } } opcodes::Ordinary::OP_EQUAL | opcodes::Ordinary::OP_EQUALVERIFY => { if stack.len() < 2 { return Err(Error::PopEmptyStack); } let a = stack.pop().unwrap(); let b = stack.pop().unwrap(); stack.push(MaybeOwned::Borrowed(if a == b { SCRIPT_TRUE } else { SCRIPT_FALSE })); if op == opcodes::Ordinary::OP_EQUALVERIFY { op_verify!(stack, Error::EqualVerifyFailed((&a[..]).to_hex(), (&b[..]).to_hex())); } } opcodes::Ordinary::OP_1ADD => { num_opcode!(stack(a): a + 1); } opcodes::Ordinary::OP_1SUB => { num_opcode!(stack(a): a - 1); } opcodes::Ordinary::OP_NEGATE => { num_opcode!(stack(a): -a); } opcodes::Ordinary::OP_ABS => { num_opcode!(stack(a): a.abs()); } opcodes::Ordinary::OP_NOT => { num_opcode!(stack(a): if a == 0 {1} else {0}); } opcodes::Ordinary::OP_0NOTEQUAL => { num_opcode!(stack(a): if a != 0 {1} else {0}); } opcodes::Ordinary::OP_ADD => { num_opcode!(stack(b, a): a + b); } opcodes::Ordinary::OP_SUB => { num_opcode!(stack(b, a): a - b); } opcodes::Ordinary::OP_BOOLAND => { num_opcode!(stack(b, a): if a != 0 && b != 0 {1} else {0}); } opcodes::Ordinary::OP_BOOLOR => { num_opcode!(stack(b, a): if a != 0 || b != 0 {1} else {0}); } opcodes::Ordinary::OP_NUMEQUAL => { num_opcode!(stack(b, a): if a == b {1} else {0}); } opcodes::Ordinary::OP_NUMNOTEQUAL => { num_opcode!(stack(b, a): if a != b {1} else {0}); } opcodes::Ordinary::OP_NUMEQUALVERIFY => { let (b, a) = num_opcode!(stack(b, a): if a == b {1} else {0}); op_verify!(stack, Error::NumEqualVerifyFailed(a, b)); } opcodes::Ordinary::OP_LESSTHAN => { num_opcode!(stack(b, a): if a < b {1} else {0}); } opcodes::Ordinary::OP_GREATERTHAN => { num_opcode!(stack(b, a): if a > b {1} else {0}); } opcodes::Ordinary::OP_LESSTHANOREQUAL => { num_opcode!(stack(b, a): if a <= b {1} else {0}); } opcodes::Ordinary::OP_GREATERTHANOREQUAL => { num_opcode!(stack(b, a): if a >= b {1} else {0}); } opcodes::Ordinary::OP_MIN => { num_opcode!(stack(b, a): if a < b {a} else {b}); } opcodes::Ordinary::OP_MAX => { num_opcode!(stack(b, a): if a > b {a} else {b}); } opcodes::Ordinary::OP_WITHIN => { num_opcode!(stack(c, b, a): if b <= a && a < c {1} else {0}); } opcodes::Ordinary::OP_RIPEMD160 => hash_opcode!(stack, Ripemd160), opcodes::Ordinary::OP_SHA1 => hash_opcode!(stack, Sha1), opcodes::Ordinary::OP_SHA256 => hash_opcode!(stack, Sha256), opcodes::Ordinary::OP_HASH160 => { hash_opcode!(stack, Sha256); hash_opcode!(stack, Ripemd160); } opcodes::Ordinary::OP_HASH256 => { hash_opcode!(stack, Sha256); hash_opcode!(stack, Sha256); } opcodes::Ordinary::OP_CODESEPARATOR => { codeseparator_index = index; } opcodes::Ordinary::OP_CHECKSIG | opcodes::Ordinary::OP_CHECKSIGVERIFY => { if stack.len() < 2 { return Err(Error::PopEmptyStack); } let pk = stack.pop().unwrap(); let pk_slice = &pk[..]; let sig = stack.pop().unwrap(); let sig_slice = &sig[..]; // Compute the section of script that needs to be hashed: everything // from the last CODESEPARATOR, except the signature itself. let mut script = (&self.0[codeseparator_index..]).to_vec(); let mut remove = Builder::new(); remove.push_slice(sig_slice); script_find_and_remove(&mut script, &remove[..]); // Also all of the OP_CODESEPARATORS, even the unevaluated ones script_find_and_remove(&mut script, &[opcodes::Ordinary::OP_CODESEPARATOR as u8]); // This is as far as we can go without a transaction, so fail here if input_context.is_none() { return Err(Error::NoTransaction); } // Otherwise unwrap it let (tx, input_index) = input_context.unwrap(); match check_signature(secp, sig_slice, pk_slice, script, tx, input_index) { Ok(()) => stack.push(MaybeOwned::Borrowed(SCRIPT_TRUE)), _ => stack.push(MaybeOwned::Borrowed(SCRIPT_FALSE)), } if op == opcodes::Ordinary::OP_CHECKSIGVERIFY { op_verify!(stack, Error::VerifyFailed); } } opcodes::Ordinary::OP_CHECKMULTISIG | opcodes::Ordinary::OP_CHECKMULTISIGVERIFY => { // Read all the keys if stack.len() < 1 { return Err(Error::PopEmptyStack); } let n_keys = try!(read_scriptint(&stack.pop().unwrap()[..])); if n_keys < 0 || n_keys > 20 { return Err(Error::MultisigBadKeyCount(n_keys as isize)); } if (stack.len() as i64) < n_keys { return Err(Error::PopEmptyStack); } let mut keys = Vec::with_capacity(n_keys as usize); for _ in 0..n_keys { keys.push(stack.pop().unwrap()); } // Read all the signatures if stack.len() < 1 { return Err(Error::PopEmptyStack); } let n_sigs = try!(read_scriptint(&stack.pop().unwrap()[..])); if n_sigs < 0 || n_sigs > n_keys { return Err(Error::MultisigBadSigCount(n_sigs as isize)); } if (stack.len() as i64) < n_sigs { return Err(Error::PopEmptyStack); } let mut sigs = Vec::with_capacity(n_sigs as usize); for _ in 0..n_sigs { sigs.push(stack.pop().unwrap()); } // Pop one more element off the stack to be replicate a consensus bug if stack.pop().is_none() { return Err(Error::PopEmptyStack); } // Compute the section of script that needs to be hashed: everything // from the last CODESEPARATOR, except the signatures themselves. let mut script = (&self.0[codeseparator_index..]).to_vec(); for sig in sigs.iter() { let mut remove = Builder::new(); remove.push_slice(&sig[..]); script_find_and_remove(&mut script, &remove[..]); script_find_and_remove(&mut script, &[opcodes::Ordinary::OP_CODESEPARATOR as u8]); } // This is as far as we can go without a transaction, so fail here if input_context.is_none() { return Err(Error::NoTransaction); } // Otherwise unwrap it let (tx, input_index) = input_context.unwrap(); // Check signatures let mut key_iter = keys.iter(); let mut sig_iter = sigs.iter(); let mut key = key_iter.next(); let mut sig = sig_iter.next(); loop { match (key, sig) { // Try to validate the signature with the given key (Some(k), Some(s)) => { // Move to the next signature if it is valid for the current key if check_signature(secp, &s[..], &k[..], script.clone(), tx, input_index).is_ok() { sig = sig_iter.next(); } // Move to the next key in any case key = key_iter.next(); } // Run out of signatures, success (_, None) => { stack.push(MaybeOwned::Borrowed(SCRIPT_TRUE)); break; } // Run out of keys to match to signatures, fail (None, Some(_)) => { stack.push(MaybeOwned::Borrowed(SCRIPT_FALSE)); break; } } } if op == opcodes::Ordinary::OP_CHECKMULTISIGVERIFY { op_verify!(stack, Error::VerifyFailed); } } } // end opcode match } // end classification match } // end loop // Store the stack in the trace trace.as_mut().map(|t| t.last_mut().map(|t| { t.errored = false; t.stack = stack.iter().map(|elem| (&elem[..]).to_hex()).collect(); }) ); } Ok(()) } /// Checks whether a script pubkey is a p2sh output #[inline] pub fn is_p2sh(&self) -> bool { self.0.len() == 23 && self.0[0] == opcodes::All::OP_HASH160 as u8 && self.0[1] == opcodes::All::OP_PUSHBYTES_20 as u8 && self.0[22] == opcodes::All::OP_EQUAL as u8 } /// Whether a script can be proven to have no satisfying input pub fn is_provably_unspendable(&self) -> bool { match self.satisfy() { Ok(_) => false, Err(Error::Unanalyzable) => false, Err(_) => 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 satisfy(&self) -> Result, Error> { fn recurse<'a>(script: &'a [u8], mut stack: AbstractStack, mut exec_stack: Vec, depth: usize) -> Result, Error> { // Avoid doing more than 64k forks if depth > 16 { return Err(Error::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 match (executing, opcodes::All::from(byte).classify()) { // Illegal operations mean failure regardless of execution state (_, opcodes::Class::IllegalOp) => return Err(Error::IllegalOpcode), // Push number (true, opcodes::Class::PushNum(n)) => { stack.push_alloc(AbstractStackElem::new_num(n as i64)); }, // Return operations mean failure, but only if executed (true, opcodes::Class::ReturnOp) => return Err(Error::ExecutedReturn), // Data-reading statements still need to read, even when not executing (_, opcodes::Class::PushBytes(n)) => { let n = n as usize; if script.len() < index + n { return Err(Error::EarlyEndOfScript); } if executing { stack.push_alloc(AbstractStackElem::new_raw(&script[index..index + n])); } index += n; } (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA1)) => { if script.len() < index + 1 { return Err(Error::EarlyEndOfScript); } let n = match read_uint(&script[index..], 1) { Ok(n) => n, Err(_) => { return Err(Error::EarlyEndOfScript); } }; if script.len() < index + 1 + n { return Err(Error::EarlyEndOfScript); } if executing { stack.push_alloc(AbstractStackElem::new_raw(&script[index + 1..index + n + 1])); } index += 1 + n; } (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA2)) => { if script.len() < index + 2 { return Err(Error::EarlyEndOfScript); } let n = match read_uint(&script[index..], 2) { Ok(n) => n, Err(_) => { return Err(Error::EarlyEndOfScript); } }; if script.len() < index + 2 + n { return Err(Error::EarlyEndOfScript); } if executing { stack.push_alloc(AbstractStackElem::new_raw(&script[index + 2..index + n + 2])); } index += 2 + n; } (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4)) => { let n = match read_uint(&script[index..], 4) { Ok(n) => n, Err(_) => { return Err(Error::EarlyEndOfScript); } }; if script.len() < index + 4 + n { return Err(Error::EarlyEndOfScript); } if executing { stack.push_alloc(AbstractStackElem::new_raw(&script[index + 4..index + n + 4])); } index += 4 + n; } // If-statements take effect when not executing (false, opcodes::Class::Ordinary(opcodes::Ordinary::OP_IF)) => exec_stack.push(false), (false, opcodes::Class::Ordinary(opcodes::Ordinary::OP_NOTIF)) => exec_stack.push(false), (false, opcodes::Class::Ordinary(opcodes::Ordinary::OP_ELSE)) => { match exec_stack.last_mut() { Some(ref_e) => { *ref_e = !*ref_e } None => { return Err(Error::ElseWithoutIf); } } } (false, opcodes::Class::Ordinary(opcodes::Ordinary::OP_ENDIF)) => { if exec_stack.pop().is_none() { return Err(Error::EndifWithoutIf); } } // No-ops and non-executed operations do nothing (true, opcodes::Class::NoOp) | (false, _) => {} // Actual opcodes (true, opcodes::Class::Ordinary(op)) => { match op { opcodes::Ordinary::OP_PUSHDATA1 | opcodes::Ordinary::OP_PUSHDATA2 | opcodes::Ordinary::OP_PUSHDATA4 => { // handled above } opcodes::Ordinary::OP_IF => { let top_bool = { let top = stack.peek_mut(); top.bool_value() }; match top_bool { None => { let mut stack_true = stack.clone(); // Try pushing false and see what happens if stack.peek_mut().set_bool_value(false).is_ok() { match recurse(&script[index - 1..], stack, exec_stack.clone(), depth + 1) { Ok(res) => { return Ok(res); } Err(_) => {} } } // Failing that, push true try!(stack_true.peek_mut().set_bool_value(true)); return recurse(&script[index - 1..], stack_true, exec_stack, depth + 1); } Some(val) => { stack.pop(); exec_stack.push(val) } } } opcodes::Ordinary::OP_NOTIF => { let top_bool = { let top = stack.peek_mut(); top.bool_value() }; match top_bool { None => { let mut stack_true = stack.clone(); // Try pushing false and see what happens if stack.peek_mut().set_bool_value(false).is_ok() { match recurse(&script[index - 1..], stack, exec_stack.clone(), depth + 1) { Ok(res) => { return Ok(res); } Err(_) => {} } } // Failing that, push true try!(stack_true.peek_mut().set_bool_value(true)); return recurse(&script[index - 1..], stack_true, exec_stack, depth + 1); } Some(val) => { stack.pop(); exec_stack.push(!val) } } } opcodes::Ordinary::OP_ELSE => { match exec_stack.last_mut() { Some(ref_e) => { *ref_e = !*ref_e } None => { return Err(Error::ElseWithoutIf); } } } opcodes::Ordinary::OP_ENDIF => { if exec_stack.pop().is_none() { return Err(Error::EndifWithoutIf); } } opcodes::Ordinary::OP_VERIFY => op_verify_satisfy!(stack), opcodes::Ordinary::OP_TOALTSTACK => { stack.to_altstack(); } opcodes::Ordinary::OP_FROMALTSTACK => { try!(stack.from_altstack()); } opcodes::Ordinary::OP_2DROP => stack_opcode!(stack(2): require 2 drop 1; drop 2), opcodes::Ordinary::OP_2DUP => stack_opcode!(stack(2): require 2 copy 2; copy 1), opcodes::Ordinary::OP_3DUP => stack_opcode!(stack(3): require 3 copy 3; copy 2; copy 1), opcodes::Ordinary::OP_2OVER => stack_opcode!(stack(4): require 4 copy 4; copy 3), opcodes::Ordinary::OP_2ROT => stack_opcode!(stack(6): require 6 perm (1, 3, 5); perm (2, 4, 6)), opcodes::Ordinary::OP_2SWAP => stack_opcode!(stack(4): require 4 swap (2, 4); swap (1, 3)), opcodes::Ordinary::OP_DROP => stack_opcode!(stack(1): require 1 drop 1), opcodes::Ordinary::OP_DUP => stack_opcode!(stack(1): require 1 copy 1), opcodes::Ordinary::OP_NIP => stack_opcode!(stack(2): require 2 drop 2), opcodes::Ordinary::OP_OVER => stack_opcode!(stack(2): require 2 copy 2), opcodes::Ordinary::OP_PICK => { 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 usize) }; 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(Error::Unanalyzable); } } } opcodes::Ordinary::OP_ROLL => { 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 usize) }; 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(Error::Unanalyzable); } } } opcodes::Ordinary::OP_ROT => stack_opcode!(stack(3): require 3 perm (1, 2, 3)), opcodes::Ordinary::OP_SWAP => stack_opcode!(stack(2): require 3 swap (1, 2)), opcodes::Ordinary::OP_TUCK => stack_opcode!(stack(2): require 2 copy 2; copy 1 drop 2), opcodes::Ordinary::OP_IFDUP => { 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(); // Try pushing false and see what happens if stack.peek_mut().set_bool_value(false).is_ok() { match recurse(&script[index - 1..], stack, exec_stack.clone(), depth + 1) { Ok(res) => { return Ok(res); } Err(_) => {} } } // Failing that, push true try!(stack_true.peek_mut().set_bool_value(true)); return recurse(&script[index - 1..], stack_true, exec_stack, depth + 1); } } } opcodes::Ordinary::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::Ordinary::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::Ordinary::OP_EQUAL => boolean_opcode_satisfy!(stack, binary op_equal), opcodes::Ordinary::OP_EQUALVERIFY => { boolean_opcode_satisfy!(stack, binary op_equal); op_verify_satisfy!(stack); } opcodes::Ordinary::OP_NOT => boolean_opcode_satisfy!(stack, unary op_not), opcodes::Ordinary::OP_0NOTEQUAL => boolean_opcode_satisfy!(stack, unary op_0notequal), opcodes::Ordinary::OP_NUMEQUAL => boolean_opcode_satisfy!(stack, binary op_numequal), opcodes::Ordinary::OP_NUMEQUALVERIFY => { boolean_opcode_satisfy!(stack, binary op_numequal); op_verify_satisfy!(stack); } opcodes::Ordinary::OP_NUMNOTEQUAL => boolean_opcode_satisfy!(stack, binary op_numnotequal), opcodes::Ordinary::OP_LESSTHAN => boolean_opcode_satisfy!(stack, binary op_numlt), opcodes::Ordinary::OP_GREATERTHAN => boolean_opcode_satisfy!(stack, binary op_numgt), opcodes::Ordinary::OP_LESSTHANOREQUAL => boolean_opcode_satisfy!(stack, binary op_numlteq), opcodes::Ordinary::OP_GREATERTHANOREQUAL => boolean_opcode_satisfy!(stack, binary op_numgteq), opcodes::Ordinary::OP_1ADD | opcodes::Ordinary::OP_1SUB | opcodes::Ordinary::OP_NEGATE | opcodes::Ordinary::OP_ABS | opcodes::Ordinary::OP_ADD | opcodes::Ordinary::OP_SUB | opcodes::Ordinary::OP_BOOLAND | opcodes::Ordinary::OP_BOOLOR | opcodes::Ordinary::OP_MIN | opcodes::Ordinary::OP_MAX | opcodes::Ordinary::OP_WITHIN => { return Err(Error::Unanalyzable); } opcodes::Ordinary::OP_RIPEMD160 => unary_opcode_satisfy!(stack, op_ripemd160), opcodes::Ordinary::OP_SHA1 => unary_opcode_satisfy!(stack, op_sha1), opcodes::Ordinary::OP_SHA256 => unary_opcode_satisfy!(stack, op_sha256), opcodes::Ordinary::OP_HASH160 => unary_opcode_satisfy!(stack, op_hash160), opcodes::Ordinary::OP_HASH256 => unary_opcode_satisfy!(stack, op_hash256), // Ignore code separators since we don't check signatures opcodes::Ordinary::OP_CODESEPARATOR => {} opcodes::Ordinary::OP_CHECKSIG => boolean_opcode_satisfy!(stack, binary op_checksig), opcodes::Ordinary::OP_CHECKSIGVERIFY => { boolean_opcode_satisfy!(stack, binary op_checksig); op_verify_satisfy!(stack); } opcodes::Ordinary::OP_CHECKMULTISIG | opcodes::Ordinary::OP_CHECKMULTISIGVERIFY => { 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 0..n_keys { let key = stack.pop_mut(); if key.may_be_pubkey() { allowable_failures += 1; } } 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 0..n_sigs { let sig = stack.pop_mut(); if !sig.may_be_signature() { allowable_failures -= 1; } if allowable_failures < 0 { return Err(Error::Unsatisfiable); } if n_sigs != n_sigs_hi { return Err(Error::Unanalyzable); } } } else { return Err(Error::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::Ordinary::OP_CHECKMULTISIGVERIFY { op_verify_satisfy!(stack); } } } } } } // If we finished, we are only unspendable if we have false on the stack 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(Error::AnalyzeAlwaysReturnsFalse) } } recurse(&self.0, AbstractStack::new(), vec![], 1) } } impl Default for Script { fn default() -> Script { Script(vec![].into_boxed_slice()) } } /// Creates a new script from an existing vector impl From> for Script { fn from(v: Vec) -> Script { Script(v.into_boxed_slice()) } } impl_index_newtype!(Script, u8); /// A "parsed opcode" which allows iterating over a Script in a more sensible way pub enum Instruction<'a> { /// Push a bunch of data PushBytes(&'a [u8]), /// Some non-push opcode Op(opcodes::All), /// An opcode we were unable to parse Error(Error) } /// Iterator over a script returning parsed opcodes pub struct Instructions<'a> { data: &'a [u8] } impl<'a> IntoIterator for &'a Script { type Item = Instruction<'a>; type IntoIter = Instructions<'a>; fn into_iter(self) -> Instructions<'a> { Instructions { data: &self.0[..] } } } impl<'a> Iterator for Instructions<'a> { type Item = Instruction<'a>; fn next(&mut self) -> Option> { if self.data.len() == 0 { return None; } match opcodes::All::from(self.data[0]).classify() { opcodes::Class::PushBytes(n) => { let n = n as usize; if self.data.len() < n + 1 { return Some(Instruction::Error(Error::EarlyEndOfScript)); } let ret = Some(Instruction::PushBytes(&self.data[1..n+1])); self.data = &self.data[n + 1..]; ret } opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA1) => { if self.data.len() < 2 { return Some(Instruction::Error(Error::EarlyEndOfScript)); } let n = match read_uint(&self.data[1..], 1) { Ok(n) => n, Err(e) => { return Some(Instruction::Error(e)); } }; if self.data.len() < n + 2 { return Some(Instruction::Error(Error::EarlyEndOfScript)); } let ret = Some(Instruction::PushBytes(&self.data[2..n+2])); self.data = &self.data[n + 2..]; ret } opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA2) => { if self.data.len() < 3 { return Some(Instruction::Error(Error::EarlyEndOfScript)); } let n = match read_uint(&self.data[1..], 2) { Ok(n) => n, Err(e) => { return Some(Instruction::Error(e)); } }; if self.data.len() < n + 3 { return Some(Instruction::Error(Error::EarlyEndOfScript)); } let ret = Some(Instruction::PushBytes(&self.data[3..n + 3])); self.data = &self.data[n + 3..]; ret } opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4) => { if self.data.len() < 5 { return Some(Instruction::Error(Error::EarlyEndOfScript)); } let n = match read_uint(&self.data[1..], 4) { Ok(n) => n, Err(e) => { return Some(Instruction::Error(e)); } }; if self.data.len() < n + 5 { return Some(Instruction::Error(Error::EarlyEndOfScript)); } let ret = Some(Instruction::PushBytes(&self.data[5..n + 5])); self.data = &self.data[n + 5..]; ret } // Everything else we can push right through _ => { let ret = Some(Instruction::Op(opcodes::All::from(self.data[0]))); self.data = &self.data[1..]; ret } } } } impl Builder { /// Creates a new empty script pub fn new() -> Builder { Builder(vec![]) } /// The length in bytes of the script pub fn len(&self) -> usize { self.0.len() } /// Adds instructions to push an integer onto the stack. Integers are /// encoded as little-endian signed-magnitude numbers, but there are /// dedicated opcodes to push some small integers. pub fn push_int(&mut self, data: i64) { // We can special-case -1, 1-16 if data == -1 || (data >= 1 && data <= 16) { self.0.push((data + opcodes::OP_TRUE as i64) as u8); } // We can also special-case zero else if data == 0 { self.0.push(opcodes::OP_FALSE as u8); } // Otherwise encode it as data else { self.push_scriptint(data); } } /// Adds instructions to push an integer onto the stack, using the explicit /// encoding regardless of the availability of dedicated opcodes. pub fn push_scriptint(&mut self, data: i64) { self.push_slice(&build_scriptint(data)); } /// Adds instructions to push some arbitrary data onto the stack pub fn push_slice(&mut self, data: &[u8]) { // Start with a PUSH opcode match data.len() { n if n < opcodes::Ordinary::OP_PUSHDATA1 as usize => { self.0.push(n as u8); }, n if n < 0x100 => { self.0.push(opcodes::Ordinary::OP_PUSHDATA1 as u8); self.0.push(n as u8); }, n if n < 0x10000 => { self.0.push(opcodes::Ordinary::OP_PUSHDATA2 as u8); self.0.push((n % 0x100) as u8); self.0.push((n / 0x100) as u8); }, n if n < 0x100000000 => { self.0.push(opcodes::Ordinary::OP_PUSHDATA4 as u8); self.0.push((n % 0x100) as u8); self.0.push(((n / 0x100) % 0x100) as u8); self.0.push(((n / 0x10000) % 0x100) as u8); self.0.push((n / 0x1000000) as u8); } _ => panic!("tried to put a 4bn+ sized object into a script!") } // Then push the acraw self.0.extend(data.iter().cloned()); } /// Adds a single opcode to the script pub fn push_opcode(&mut self, data: opcodes::All) { self.0.push(data as u8); } /// Converts the `Builder` into an unmodifiable `Script` pub fn into_script(self) -> Script { Script(self.0.into_boxed_slice()) } } /// Adds an individual opcode to the script impl Default for Builder { fn default() -> Builder { Builder(vec![]) } } /// Creates a new script from an existing vector impl From> for Builder { fn from(v: Vec) -> Builder { Builder(v) } } impl_index_newtype!(Builder, u8); // User-facing serialization impl serde::Serialize for Script { fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: serde::Serializer, { for dat in self.0.iter() { try!(serializer.visit_char(from_digit((dat / 0x10) as u32, 16).unwrap())); try!(serializer.visit_char(from_digit((dat & 0x0f) as u32, 16).unwrap())); } Ok(()) } } // Network serialization impl ConsensusEncodable for Script { #[inline] fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { self.0.consensus_encode(s) } } impl ConsensusDecodable for Script { #[inline] fn consensus_decode(d: &mut D) -> Result { Ok(Script(try!(ConsensusDecodable::consensus_decode(d)))) } } #[cfg(test)] mod test { use secp256k1::Secp256k1; use serialize::hex::FromHex; use super::*; use super::build_scriptint; use super::MaybeOwned::Owned; use network::serialize::{deserialize, serialize}; use blockdata::opcodes; use blockdata::transaction::Transaction; fn test_tx(tx_hex: &'static str, output_hex: Vec<&'static str>) { let s = Secp256k1::new(); let tx_hex = tx_hex.from_hex().unwrap(); let tx: Transaction = deserialize(&tx_hex).ok().expect("transaction"); let script_pk: Vec