From 200e0fe8e3147d1b18ca0ff7f4b40ad69f68ca58 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Mon, 6 Apr 2015 20:51:11 -0500 Subject: [PATCH] Checkpoint commit 27 files changed, 3944 insertions(+), 3812 deletions(-) :} I've started doing whitespace changes as well, I want everything to be 4-space tabs from now on. --- src/blockdata/block.rs | 12 +- src/blockdata/blockchain.rs | 20 +- src/blockdata/opcodes.rs | 5 + src/blockdata/script.rs | 4763 +++++++++++++++--------------- src/blockdata/transaction.rs | 16 +- src/blockdata/utxoset.rs | 6 +- src/internal_macros.rs | 306 +- src/macros.rs | 8 + src/network/address.rs | 14 +- src/network/constants.rs | 50 +- src/network/encodable.rs | 684 ++--- src/network/listener.rs | 127 +- src/network/message.rs | 312 +- src/network/message_blockdata.rs | 6 +- src/network/message_network.rs | 131 +- src/network/serialize.rs | 182 +- src/network/socket.rs | 263 +- src/util/base58.rs | 21 +- src/util/error.rs | 38 - src/util/hash.rs | 38 +- src/util/misc.rs | 56 +- src/util/mod.rs | 56 +- src/util/patricia_tree.rs | 64 +- src/util/uint.rs | 96 +- src/wallet/address.rs | 66 +- src/wallet/address_index.rs | 18 +- src/wallet/bip32.rs | 184 +- src/wallet/wallet.rs | 34 +- 28 files changed, 3835 insertions(+), 3741 deletions(-) delete mode 100644 src/util/error.rs diff --git a/src/blockdata/block.rs b/src/blockdata/block.rs index 0585be6..88aebb2 100644 --- a/src/blockdata/block.rs +++ b/src/blockdata/block.rs @@ -22,8 +22,8 @@ use std::num::{Zero, from_u64}; -use util::error; -use util::error::Error::{SpvBadTarget, SpvBadProofOfWork}; +use util; +use util::Error::{SpvBadTarget, SpvBadProofOfWork}; use util::hash::Sha256dHash; use util::uint::Uint256; use network::encodable::{ConsensusEncodable, VarInt}; @@ -97,7 +97,7 @@ impl BlockHeader { /// Performs an SPV validation of a block, which confirms that the proof-of-work /// is correct, but does not verify that the transactions are valid or encoded /// correctly. - pub fn spv_validate(&self, required_target: &Uint256) -> Result<(), error::Error> { + pub fn spv_validate(&self, required_target: &Uint256) -> Result<(), util::Error> { let ref target = self.target(); if target != required_target { return Err(SpvBadTarget); @@ -137,7 +137,7 @@ impl_consensus_encoding!(LoneBlockHeader, header, tx_count); #[cfg(test)] mod tests { - use std::io::IoResult; + use std::io; use serialize::hex::FromHex; use blockdata::block::Block; @@ -151,8 +151,8 @@ mod tests { let prevhash = "4ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000".from_hex().unwrap(); let merkle = "bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914c".from_hex().unwrap(); - let decode: IoResult = deserialize(some_block.clone()); - let bad_decode: IoResult = deserialize(cutoff_block); + let decode: io::Result = deserialize(some_block.clone()); + let bad_decode: io::Result = deserialize(cutoff_block); assert!(decode.is_ok()); assert!(bad_decode.is_err()); diff --git a/src/blockdata/blockchain.rs b/src/blockdata/blockchain.rs index c8168a2..770f36e 100644 --- a/src/blockdata/blockchain.rs +++ b/src/blockdata/blockchain.rs @@ -33,8 +33,8 @@ use network::constants::Network; use network::encodable::{ConsensusDecodable, ConsensusEncodable}; use network::serialize::{BitcoinHash, SimpleDecoder, SimpleEncoder}; use util::BitArray; -use util::error; -use util::error::Error::{BlockNotFound, DuplicateHash, PrevHashNotFound}; +use util; +use util::Error::{BlockNotFound, DuplicateHash, PrevHashNotFound}; use util::uint::Uint256; use util::hash::Sha256dHash; use util::patricia_tree::PatriciaTree; @@ -373,7 +373,7 @@ impl Blockchain { } } - fn replace_txdata(&mut self, hash: &Uint256, txdata: Vec, has_txdata: bool) -> Result<(), error::Error> { + fn replace_txdata(&mut self, hash: &Uint256, txdata: Vec, has_txdata: bool) -> Result<(), util::Error> { match self.tree.lookup_mut(hash, 256) { Some(existing_block) => { unsafe { @@ -413,26 +413,26 @@ impl Blockchain { } /// Locates a block in the chain and overwrites its txdata - pub fn add_txdata(&mut self, block: Block) -> Result<(), error::Error> { + pub fn add_txdata(&mut self, block: Block) -> Result<(), util::Error> { self.replace_txdata(&block.header.bitcoin_hash().into_le(), block.txdata, true) } /// Locates a block in the chain and removes its txdata - pub fn remove_txdata(&mut self, hash: Sha256dHash) -> Result<(), error::Error> { + pub fn remove_txdata(&mut self, hash: Sha256dHash) -> Result<(), util::Error> { self.replace_txdata(&hash.into_le(), vec![], false) } /// Adds a block header to the chain - pub fn add_header(&mut self, header: BlockHeader) -> Result<(), error::Error> { + pub fn add_header(&mut self, header: BlockHeader) -> Result<(), util::Error> { self.real_add_block(Block { header: header, txdata: vec![] }, false) } /// Adds a block to the chain - pub fn add_block(&mut self, block: Block) -> Result<(), error::Error> { + pub fn add_block(&mut self, block: Block) -> Result<(), util::Error> { self.real_add_block(block, true) } - fn real_add_block(&mut self, block: Block, has_txdata: bool) -> Result<(), error::Error> { + fn real_add_block(&mut self, block: Block, has_txdata: bool) -> Result<(), util::Error> { // get_prev optimizes the common case where we are extending the best tip #[inline] fn get_prev<'a>(chain: &'a Blockchain, hash: Sha256dHash) -> Option { @@ -618,7 +618,7 @@ impl Blockchain { #[cfg(test)] mod tests { - use std::io::IoResult; + use std::io; use blockdata::blockchain::Blockchain; use blockdata::constants::genesis_block; @@ -632,7 +632,7 @@ mod tests { genesis_block(Bitcoin).header.bitcoin_hash()); let serial = serialize(&empty_chain); - let deserial: IoResult = deserialize(serial.unwrap()); + let deserial: io::Result = deserialize(serial.unwrap()); assert!(deserial.is_ok()); let read_chain = deserial.unwrap(); diff --git a/src/blockdata/opcodes.rs b/src/blockdata/opcodes.rs index ae78e71..da66ba7 100644 --- a/src/blockdata/opcodes.rs +++ b/src/blockdata/opcodes.rs @@ -24,6 +24,7 @@ use serde; // Heavy stick to translate between opcode types use std::mem::transmute; +use std::fmt; use network::serialize::{SimpleDecoder, SimpleEncoder}; use network::encodable::{ConsensusDecodable, ConsensusEncodable}; @@ -602,6 +603,8 @@ impl All { } } +display_from_debug!(All); + impl ConsensusDecodable for All { #[inline] fn consensus_decode(d: &mut D) -> Result { @@ -646,6 +649,8 @@ pub enum Class { Ordinary(Ordinary) } +display_from_debug!(Class); + impl serde::Serialize for Class { fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: serde::Serializer, diff --git a/src/blockdata/script.rs b/src/blockdata/script.rs index c8e2eba..6370dfd 100644 --- a/src/blockdata/script.rs +++ b/src/blockdata/script.rs @@ -1,6 +1,6 @@ // Rust Bitcoin Library // Written in 2014 by -// Andrew Poelstra +// Andrew Poelstra // // To the extent possible under law, the author(s) have dedicated all // copyright and related and neighboring rights to this software to @@ -46,28 +46,34 @@ use network::serialize::{SimpleDecoder, SimpleEncoder, serialize}; use util::hash::Sha256dHash; use util::misc::script_find_and_remove; -#[derive(PartialEq, Eq, Debug, Clone)] +#[derive(PartialEq, Eq, Debug)] /// A Bitcoin script pub struct Script(Box<[u8]>); -impl hash::Hash for Script { - #[inline] - fn hash(&self, state: &mut H) - where H: hash::Hasher - { - let &Script(ref raw) = self; - (&raw[..]).hash(state); - } - - #[inline] - fn hash_slice(data: &[Script], state: &mut H) - where H: hash::Hasher - { - for s in data.iter() { - let &Script(ref raw) = s; - (&raw[..]).hash(state); +impl Clone for Script { + fn clone(&self) -> Script { + Script(self.0.to_vec().into_boxed_slice()) + } +} + +impl hash::Hash for Script { + #[inline] + fn hash(&self, state: &mut H) + where H: hash::Hasher + { + let &Script(ref raw) = self; + (&raw[..]).hash(state); + } + + #[inline] + fn hash_slice(data: &[Script], state: &mut H) + where H: hash::Hasher + { + for s in data.iter() { + let &Script(ref raw) = s; + (&raw[..]).hash(state); + } } - } } /// Ways that a script might fail. Not everything is split up as @@ -75,1289 +81,1337 @@ impl hash::Hash for Script { /// 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, + /// 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> + /// 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 + fn clone(&self) -> Validator { + Validator { + args: self.args.clone(), + check: self.check, + update: self.update + } } - } } // Validators fn check_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 + 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: &[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) + -> 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 check_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()) + 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()) + } } - 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<(), 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) - } +fn update_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) + } } fn update_op_equal(elem: &mut AbstractStackElem, others: &[usize]) - -> Result<(), Error> { - 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(Error::Unsatisfiable), - (Some(_), Some(_)) => Ok(()) - } + -> Result<(), Error> { + 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(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(()) + } } - 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(()) - } - } } fn check_op_not(elem: &AbstractStackElem, others: &[usize]) -> bool { - let one = unsafe { elem.lookup(others[0]) }; - if !one.may_be_numeric() { - return false; - } + 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 - } + 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: &[usize]) - -> Result<(), Error> { - 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(Error::Unsatisfiable) - } + -> Result<(), Error> { + 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(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(()) + } + } } - 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(()) - } - } - } } fn check_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 - } + 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: &[usize]) - -> Result<(), Error> { - 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(Error::Unsatisfiable), - Some(false) => Ok(()) - } + -> Result<(), Error> { + 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(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) + } + } } - 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) - } - } - } } fn check_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()) + 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()) + } } - 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: &[usize]) - -> Result<(), Error> { - match elem.bool_value() { - None => update_boolean(elem), - Some(false) => { - // todo: find a way to force the numbers to be nonequal - Ok(()) + -> Result<(), Error> { + 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()) + } } - 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: &[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) - } + 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: &[usize]) - -> Result<(), Error> { - 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()) + -> Result<(), Error> { + 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(()) + } } - Some(true) => { - // todo: find a way to force the numbers to be nonequal - Ok(()) - } - } } fn check_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), - } + 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: &[usize]) - -> Result<(), Error> { - 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()); + -> Result<(), Error> { + 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_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()) + try!(one.set_num_lo(two.num_lo())); + two.set_num_hi(one.num_hi()) + } } - } } fn check_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) - } + 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: &[usize]) - -> Result<(), Error> { - 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()); + -> Result<(), Error> { + 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_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())); + try!(one.set_num_hi(two.num_hi())); + try!(two.set_num_lo(one.num_lo())); + } } - } - Ok(()) + Ok(()) } fn check_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) - } + 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: &[usize]) - -> Result<(), Error> { - 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()); + -> Result<(), Error> { + 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_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)); + try!(one.set_num_lo(two.num_lo() + 1)); + try!(two.set_num_hi(one.num_hi() - 1)); + } } - } - Ok(()) + Ok(()) } fn check_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) - } + 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: &[usize]) - -> Result<(), Error> { - 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()); + -> Result<(), Error> { + 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_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)); + try!(one.set_num_hi(two.num_hi() - 1)); + try!(two.set_num_lo(one.num_lo() + 1)); + } } - } - Ok(()) + Ok(()) } fn check_op_ripemd160(elem: &AbstractStackElem, _: &[usize]) -> bool { - elem.may_be_hash160() + elem.may_be_hash160() } fn update_op_ripemd160(elem: &mut AbstractStackElem, others: &[usize]) - -> Result<(), Error> { - try!(elem.set_len_lo(20)); - try!(elem.set_len_hi(20)); + -> 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(out.as_mut_slice()); - Some(out) + 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) } - }; - - match hash { - None => Ok(()), - Some(x) => elem.set_value(&x) - } } fn check_op_sha1(elem: &AbstractStackElem, _: &[usize]) -> bool { - elem.may_be_hash160() + elem.may_be_hash160() } fn update_op_sha1(elem: &mut AbstractStackElem, others: &[usize]) - -> Result<(), Error> { - try!(elem.set_len_lo(20)); - try!(elem.set_len_hi(20)); + -> 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(out.as_mut_slice()); - Some(out) + 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) } - }; - - match hash { - None => Ok(()), - Some(x) => elem.set_value(&x) - } } fn check_op_hash160(elem: &AbstractStackElem, _: &[usize]) -> bool { - elem.may_be_hash160() + elem.may_be_hash160() } fn update_op_hash160(elem: &mut AbstractStackElem, others: &[usize]) - -> Result<(), Error> { - try!(elem.set_len_lo(20)); - try!(elem.set_len_hi(20)); + -> 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) + 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) } - }; - - match hash { - None => Ok(()), - Some(x) => elem.set_value(&x) - } } fn check_op_sha256(elem: &AbstractStackElem, _: &[usize]) -> bool { - elem.may_be_hash256() + elem.may_be_hash256() } fn update_op_sha256(elem: &mut AbstractStackElem, others: &[usize]) - -> Result<(), Error> { - try!(elem.set_len_lo(32)); - try!(elem.set_len_hi(32)); + -> 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(out.as_mut_slice()); - Some(out) + 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) } - }; - - match hash { - None => Ok(()), - Some(x) => elem.set_value(&x) - } } fn check_op_hash256(elem: &AbstractStackElem, _: &[usize]) -> bool { - elem.may_be_hash256() + elem.may_be_hash256() } fn update_op_hash256(elem: &mut AbstractStackElem, others: &[usize]) -> Result<(), Error> { - try!(elem.set_len_lo(32)); - try!(elem.set_len_hi(32)); + 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) + 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) } - }; - - match hash { - None => Ok(()), - Some(x) => elem.set_value(&x) - } } fn check_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() - } + 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: &[usize]) - -> Result<(), Error> { - 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]) }; + -> Result<(), Error> { + 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) + // 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 + /// 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().map(|v| v.clone()) { - 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)); + /// 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 } - 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) - } + /// Create a new exact boolean + pub fn new_bool(b: bool) -> AbstractStackElem { + AbstractStackElem::new_num(if b { 1 } else { 0 }) + } - /// 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(_) => {} + /// 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().map(|v| v.clone()) { + try!((v.update)(self, &v.args)); } - 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) - } + /// 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; } - /// 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() - } - - /// 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()); + self.validators.iter().all(|rule| (rule.check)(self, &rule.args)) } - 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()); + /// 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(()) } - 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()); + /// 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) } - 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()); + /// 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(()) + } + } } - Ok(()) - } - /// Adds some condition on the element - pub fn add_validator(&mut self, cond: Validator) -> Result<(), Error> { - self.validators.push(cond); - self.update() - } + /// 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 { + ((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() + } + + /// 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 + /// 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()); - } - } - - /// Lookup an element by index - pub fn get_elem(&self, alloc_index: usize) -> &AbstractStackElem { - &self.alloc[alloc_index] - } - - /// Lookup an element by index - pub fn get_elem_mut(&mut self, alloc_index: usize) -> &mut AbstractStackElem { - self.alloc.get_mut(alloc_index) - } - - /// 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); - 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()); + /// Construct a new empty abstract stack + pub fn new() -> AbstractStack { + AbstractStack { + stack: vec![], + alt_stack: vec![], + initial_stack: vec![], + alloc: vec![] + } } - self.alloc.get_mut(*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()); + fn allocate(&mut self, mut elem: AbstractStackElem) -> usize { + elem.alloc_index = Some(self.alloc.len()); + self.alloc.push(elem); + self.alloc.len() - 1 } - 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()); + fn push_initial(&mut self, elem: AbstractStackElem) { + let idx = self.allocate(elem); + self.initial_stack.insert(0, idx); + self.stack.insert(0, idx); } - 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) + /// 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 } - } - /// 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 [usize] { - self.stack.as_slice() - } + /// 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()); + } + } - /// Immutable view of the current stack as a slice of bytes - pub fn slice_to<'a>(&'a self, n: usize) -> &'a [usize] { - self.stack.slice_to(n) - } + /// Push a copy of an existing element by index + pub fn push(&mut self, elem: usize) { + self.stack.push(elem); + } - /// 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 [usize] { - self.stack.as_mut_slice() - } + /// 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] + } - /// 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); - } + /// 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()) - } + 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 + 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 + /// 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 + /// 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) - } + /// 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]) + /// 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[..] } + #[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; + type Output = u8; - #[inline] - fn index(&self, index: usize) -> &u8 { - match *self { - MaybeOwned::Owned(ref v) => &v[index], - MaybeOwned::Borrowed(ref s) => &s[index] + #[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]; + 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] + #[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]; + 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] + #[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]; + 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] + #[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]; + type Output = [u8]; - #[inline] - fn index(&self, _: ops::RangeFull) -> &[u8] { - match *self { - MaybeOwned::Owned(ref v) => &v[..], - MaybeOwned::Borrowed(ref s) => &s[..] + #[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() + /// 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]; @@ -1365,28 +1419,28 @@ 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![] } + if n == 0 { return vec![] } - let neg = n < 0; + 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 + 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 @@ -1404,39 +1458,39 @@ fn build_scriptint(n: i64) -> Vec { /// 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 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) + 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))) + !(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); + 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) } - Ok(ret) - } } /// Check a signature -- returns an error that is currently just translated @@ -1444,90 +1498,90 @@ pub fn read_uint(data: &[u8], size: usize) -> Result { fn check_signature(sig_slice: &[u8], pk_slice: &[u8], script: Vec, tx: &Transaction, input_index: usize) -> Result<(), Error> { - // Check public key - let pubkey = PublicKey::from_slice(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); + // Check public key + let pubkey = PublicKey::from_slice(pk_slice); + if pubkey.is_err() { + return Err(Error::BadPublicKey); } - } + let pubkey = pubkey.unwrap(); - // 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).unwrap()); - tx_copy.output = new_outs; - } else { - sighash_single_bug = true; - } + // Check signature and hashtype + if sig_slice.len() == 0 { + return Err(Error::BadSignature); } - SigHashType::All | SigHashType::Unknown => {} - } + let (hashtype, anyone_can_pay) = SigHashType::from_signature(sig_slice); - 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() - }; + // 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() }; - Secp256k1::verify_raw(&signature_hash[..], sig_slice, &pubkey).map_err(Error::Ecdsa) + // 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).unwrap()); + 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() + }; + + Secp256k1::verify_raw(&signature_hash[..], sig_slice, &pubkey).map_err(Error::Ecdsa) } // Macro to translate English stack instructions into Rust code. @@ -1540,1274 +1594,1293 @@ fn check_signature(sig_slice: &[u8], pk_slice: &[u8], script: Vec, // 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 - $( $stack.as_mut_slice().swap(top - $a, top - $b); )* - // Do permutations - $( let first = $first; - $( $stack.as_mut_slice().swap(top - first, top - $i); )* )* - // Do drops last so that dropped values will be available above - $( $stack.remove(top - $d); )* - }); + ($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 ),*) - }); + ($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: concat_idents!(check_, $op), - update: concat_idents!(update_, $op) })); - }) + ($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) })); - }); + ($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) })); + }); } /// 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(ret.as_mut_slice()); - $stack.push(MaybeOwned::Owned(ret)); - } - } - }); + ($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(); } - } - ) + ($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(); - }) + ($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()) } + /// Creates a new empty script + pub fn new() -> Script { Script(vec![].into_boxed_slice()) } - /// Creates a new script from an existing vector - pub fn from_vec(v: Vec) -> Script { Script(v.into_boxed_slice()) } + /// Creates a new script from an existing vector + pub fn from_vec(v: Vec) -> Script { Script(v.into_boxed_slice()) } - /// The length in bytes of the script - pub fn len(&self) -> usize { - let &Script(ref raw) = self; - raw.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) { - let &Script(ref mut raw) = self; - raw.push(data as u8 + opcodes::All::OP_TRUE as u8); - return; + /// The length in bytes of the script + pub fn len(&self) -> usize { + let &Script(ref raw) = self; + raw.len() } - // We can also special-case zero - if data == 0 { - let &Script(ref mut raw) = self; - raw.push(opcodes::All::OP_FALSE as u8); - return; + + /// 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) { + let &Script(ref mut raw) = self; + raw.push(data as u8 + opcodes::All::OP_TRUE as u8); + return; + } + // We can also special-case zero + if data == 0 { + let &Script(ref mut raw) = self; + raw.push(opcodes::All::OP_FALSE as u8); + return; + } + // Otherwise encode it as data + self.push_scriptint(data); } - // Otherwise encode it as data - 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]) { - let &Script(ref mut raw) = self; - // Start with a PUSH opcode - match data.len() { - n if n < opcodes::Ordinary::OP_PUSHDATA1 as usize => { raw.push(n as u8); }, - n if n < 0x100 => { - raw.push(opcodes::Ordinary::OP_PUSHDATA1 as u8); - raw.push(n as u8); - }, - n if n < 0x10000 => { - raw.push(opcodes::Ordinary::OP_PUSHDATA2 as u8); - raw.push((n % 0x100) as u8); - raw.push((n / 0x100) as u8); - }, - n if n < 0x100000000 => { - raw.push(opcodes::Ordinary::OP_PUSHDATA4 as u8); - raw.push((n % 0x100) as u8); - raw.push(((n / 0x100) % 0x100) as u8); - raw.push(((n / 0x10000) % 0x100) as u8); - raw.push((n / 0x1000000) as u8); - } - _ => panic!("tried to put a 4bn+ sized object into a script!") + /// 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)); } - // Then push the acraw - raw.extend(data.iter().map(|n| *n)); - } - /// Adds an individual opcode to the script - pub fn push_opcode(&mut self, data: opcodes::All) { - let &Script(ref mut raw) = self; - raw.push(data as u8); - } - - /// Returns a view into the script as a slice - pub fn as_slice(&self) -> &[u8] { - let &Script(ref raw) = self; - raw.as_slice() - } - - /// Returns a view into the script as a slice - pub fn slice_to(&self, n: usize) -> &[u8] { - let &Script(ref raw) = self; - raw.slice_to(n) - } - - /// Returns a view into the script as a slice - pub fn slice_from(&self, n: usize) -> &[u8] { - let &Script(ref raw) = self; - raw.slice_from(n) - } - - /// Returns a view into the script as a slice - pub fn slice(&self, s: usize, e: usize) -> &[u8] { - let &Script(ref raw) = self; - raw.slice(s, e) - } - - /// Trace a script - pub fn trace<'a>(&'a self, 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(stack, input_context, Some(&mut trace.iterations)) { - Ok(_) => {}, - Err(e) => { trace.error = Some(e.clone()); } + /// Adds instructions to push some arbitrary data onto the stack + pub fn push_slice(&mut self, data: &[u8]) { + let &Script(ref mut raw) = self; + // Start with a PUSH opcode + match data.len() { + n if n < opcodes::Ordinary::OP_PUSHDATA1 as usize => { raw.push(n as u8); }, + n if n < 0x100 => { + raw.push(opcodes::Ordinary::OP_PUSHDATA1 as u8); + raw.push(n as u8); + }, + n if n < 0x10000 => { + raw.push(opcodes::Ordinary::OP_PUSHDATA2 as u8); + raw.push((n % 0x100) as u8); + raw.push((n / 0x100) as u8); + }, + n if n < 0x100000000 => { + raw.push(opcodes::Ordinary::OP_PUSHDATA4 as u8); + raw.push((n % 0x100) as u8); + raw.push(((n / 0x100) % 0x100) as u8); + raw.push(((n / 0x10000) % 0x100) as u8); + raw.push((n / 0x1000000) as u8); + } + _ => panic!("tried to put a 4bn+ sized object into a script!") + } + // Then push the acraw + raw.extend(data.iter().map(|n| *n)); } - trace - } - /// Evaluate the script, modifying the stack in place - pub fn evaluate<'a>(&'a self, stack: &mut Vec>, - input_context: Option<(&Transaction, usize)>, - mut trace: Option<&mut Vec>) - -> Result<(), Error> { - let &Script(ref raw) = self; + /// Adds an individual opcode to the script + pub fn push_opcode(&mut self, data: opcodes::All) { + let &Script(ref mut raw) = self; + raw.push(data as u8); + } - let mut codeseparator_index = 0; - let mut exec_stack = vec![]; - let mut alt_stack = vec![]; + /// Trace a script + pub fn trace<'a>(&'a self, 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 + }; - let mut index = 0; - let mut op_count = 0; - while index < raw.len() { - let executing = exec_stack.iter().all(|e| *e); - let byte = unsafe { *raw.get(index) }; - // Write out the trace, except the stack which we don't know yet - match trace { - Some(ref mut t) => { - let opcode = opcodes::All::Opcode::from_u8(byte); - t.push(TraceIteration { - index: index, - opcode: opcode, - executed: executing, - errored: true, - op_count: op_count, - effect: opcode.classify(), - stack: vec!["".to_string()] - }); + match self.evaluate(stack, input_context, Some(&mut trace.iterations)) { + Ok(_) => {}, + Err(e) => { trace.error = Some(e.clone()); } } - None => {} - } - op_count += 1; - index += 1; - // The definitions of all these categories are in opcodes.rs -//println!("read {} as {} as {} ... stack before op is {}", byte, opcodes::All::Opcode::from_u8(byte), opcodes::All::Opcode::from_u8(byte).classify(), stack); - match (executing, opcodes::All::Opcode::from_u8(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)) => { - if raw.len() < index + n { return Err(Error::EarlyEndOfScript); } - if executing { stack.push(MaybeOwned::Borrowed(raw.slice(index, index + n))); } - index += n; - } - (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA1)) => { - if raw.len() < index + 1 { return Err(Error::EarlyEndOfScript); } - let n = try!(read_uint(raw.slice_from(index).iter(), 1)); - if raw.len() < index + 1 + n { return Err(Error::EarlyEndOfScript); } - if executing { stack.push(MaybeOwned::Borrowed(raw.slice(index + 1, index + n + 1))); } - index += 1 + n; - } - (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA2)) => { - if raw.len() < index + 2 { return Err(Error::EarlyEndOfScript); } - let n = try!(read_uint(raw.slice_from(index).iter(), 2)); - if raw.len() < index + 2 + n { return Err(Error::EarlyEndOfScript); } - if executing { stack.push(MaybeOwned::Borrowed(raw.slice(index + 2, index + n + 2))); } - index += 2 + n; - } - (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4)) => { - if raw.len() < index + 4 { return Err(Error::EarlyEndOfScript); } - let n = try!(read_uint(raw.slice_from(index).iter(), 4)); - if raw.len() < index + 4 + n { return Err(Error::EarlyEndOfScript); } - if executing { stack.push(MaybeOwned::Borrowed(raw.slice(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); } + trace + } - let pk = stack.pop().unwrap(); - let pk_slice = &pk[..]; - let sig = stack.pop().unwrap(); - let sig_slice = &sig[..]; + /// Evaluate the script, modifying the stack in place + pub fn evaluate<'a>(&'a self, stack: &mut Vec>, + input_context: Option<(&Transaction, usize)>, + mut trace: Option<&mut Vec>) + -> Result<(), Error> { + let &Script(ref raw) = self; - // Compute the section of script that needs to be hashed: everything - // from the last CODESEPARATOR, except the signature itself. - let mut script = raw.slice_from(codeseparator_index).to_vec(); - let mut remove = Script::new(); - remove.push_slice(sig_slice); - script_find_and_remove(&mut script, &remove); - script_find_and_remove(&mut script, [opcodes::Ordinary::OP_CODESEPARATOR as u8]); + let mut codeseparator_index = 0; + let mut exec_stack = vec![]; + let mut alt_stack = vec![]; - // 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( 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); } + let mut index = 0; + let mut op_count = 0; + while index < raw.len() { + let executing = exec_stack.iter().all(|e| *e); + let byte = unsafe { *raw.get(index) }; + // Write out the trace, except the stack which we don't know yet + match trace { + Some(ref mut t) => { + let opcode = opcodes::All::Opcode::from_u8(byte); + t.push(TraceIteration { + index: index, + opcode: opcode, + executed: executing, + errored: true, + op_count: op_count, + effect: opcode.classify(), + stack: vec!["".to_string()] + }); + } + None => {} } - 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 = raw.slice_from(codeseparator_index).to_vec(); - for sig in sigs.iter() { - let mut remove = Script::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(&s, &k, script.clone(), tx, input_index).is_ok() { - sig = sig_iter.next(); + op_count += 1; + index += 1; + // The definitions of all these categories are in opcodes.rs + match (executing, opcodes::All::Opcode::from_u8(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)) => { + if raw.len() < index + n { return Err(Error::EarlyEndOfScript); } + if executing { stack.push(MaybeOwned::Borrowed(raw.slice(index, index + n))); } + index += n; + } + (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA1)) => { + if raw.len() < index + 1 { return Err(Error::EarlyEndOfScript); } + let n = try!(read_uint(&raw[index..], 1)); + if raw.len() < index + 1 + n { return Err(Error::EarlyEndOfScript); } + if executing { stack.push(MaybeOwned::Borrowed(raw.slice(index + 1, index + n + 1))); } + index += 1 + n; + } + (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA2)) => { + if raw.len() < index + 2 { return Err(Error::EarlyEndOfScript); } + let n = try!(read_uint(&raw[index..], 2)); + if raw.len() < index + 2 + n { return Err(Error::EarlyEndOfScript); } + if executing { stack.push(MaybeOwned::Borrowed(raw.slice(index + 2, index + n + 2))); } + index += 2 + n; + } + (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4)) => { + if raw.len() < index + 4 { return Err(Error::EarlyEndOfScript); } + let n = try!(read_uint(&raw[index..], 4)); + if raw.len() < index + 4 + n { return Err(Error::EarlyEndOfScript); } + if executing { stack.push(MaybeOwned::Borrowed(raw.slice(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); } } - // 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 { - let &Script(ref raw) = self; - unsafe { - raw.len() == 23 && - *raw.get(0) == opcodes::All::OP_HASH160 as u8 && - *raw.get(1) == opcodes::All::OP_PUSHBYTES_20 as u8 && - *raw.get(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 -//println!("read {} as {} as {}", byte, opcodes::All::Opcode::from_u8(byte), opcodes::All::Opcode::from_u8(byte).classify()); - match (executing, opcodes::All::from_u8(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)) => { - if script.len() < index + n { return Err(Error::EarlyEndOfScript); } - if executing { - stack.push_alloc(AbstractStackElem::new_raw(script.slice(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.slice_from(index).iter(), 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.slice(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.slice_from(index).iter(), 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.slice(index + 2, index + n + 2))); - } - index += 2 + n; - } - (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4)) => { - let n = match read_uint(script.slice_from(index).iter(), 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.slice(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.slice_from(index - 1), stack, exec_stack.clone(), depth + 1) { - Ok(res) => { return Ok(res); } - Err(_) => {} - } + (false, opcodes::Class::Ordinary(opcodes::Ordinary::OP_ENDIF)) => { + if exec_stack.pop().is_none() { + return Err(Error::EndifWithoutIf); } - // Failing that, push true - try!(stack_true.peek_mut().set_bool_value(true)); - return recurse(script.slice_from(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.slice_from(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.slice_from(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.slice_from(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.slice_from(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()) } + // 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); } - // If it's a VERIFY op, assume it passed and carry on - if op == opcodes::Ordinary::OP_CHECKMULTISIGVERIFY { - op_verify_satisfy!(stack); - } - } - } - } + 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 = (&raw[codeseparator_index..]).to_vec(); + let mut remove = Script::new(); + remove.push_slice(sig_slice); + 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(); + + match check_signature( 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 = (&raw[codeseparator_index..]).to_vec(); + for sig in sigs.iter() { + let mut remove = Script::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(&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(); + }) + ); } - } - // 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) - } + Ok(()) } - let &Script(ref raw) = self; - recurse(&raw, AbstractStack::new(), vec![], 1) - } + /// Checks whether a script pubkey is a p2sh output + #[inline] + pub fn is_p2sh(&self) -> bool { + let &Script(ref raw) = self; + unsafe { + raw.len() == 23 && + *raw.get(0) == opcodes::All::OP_HASH160 as u8 && + *raw.get(1) == opcodes::All::OP_PUSHBYTES_20 as u8 && + *raw.get(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_u8(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)) => { + if script.len() < index + n { return Err(Error::EarlyEndOfScript); } + if executing { + stack.push_alloc(AbstractStackElem::new_raw(script.slice(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.slice(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.slice(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.slice(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) + } + } + + let &Script(ref raw) = self; + recurse(&raw, AbstractStack::new(), vec![], 1) + } } impl Default for Script { - fn default() -> Script { Script(vec![].into_boxed_slice()) } + fn default() -> Script { Script(vec![].into_boxed_slice()) } +} + + +impl ops::Index for Script { + type Output = u8; + #[inline] + fn index(&self, index: usize) -> &u8 { + let &Script(ref raw) = self; + &raw[index] + } +} + +impl ops::Index> for Script { + type Output = [u8]; + #[inline] + fn index(&self, index: ops::Range) -> &[u8] { + let &Script(ref raw) = self; + &raw[index] + } +} + +impl ops::Index> for Script { + type Output = [u8]; + #[inline] + fn index(&self, index: ops::RangeTo) -> &[u8] { + let &Script(ref raw) = self; + &raw[index] + } +} + +impl ops::Index> for Script { + type Output = [u8]; + #[inline] + fn index(&self, index: ops::RangeFrom) -> &[u8] { + let &Script(ref raw) = self; + &raw[index] + } +} + +impl ops::Index for Script { + type Output = [u8]; + #[inline] + fn index(&self, _: ops::RangeFull) -> &[u8] { + let &Script(ref raw) = self; + &raw[..] + } } // User-facing serialization impl serde::Serialize for Script { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> - where S: serde::Serializer, - { - let &Script(ref raw) = self; - for dat in raw.iter() { - serializer.visit_char(from_digit((dat / 0x10) as usize, 16).unwrap()); - serializer.visit_char(from_digit((dat & 0x0f) as usize, 16).unwrap()); + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + where S: serde::Serializer, + { + let &Script(ref raw) = self; + for dat in raw.iter() { + serializer.visit_char(from_digit((dat / 0x10) as u32, 16).unwrap()); + serializer.visit_char(from_digit((dat & 0x0f) as u32, 16).unwrap()); + } } - } } // Network serialization impl ConsensusEncodable for Script { - #[inline] - fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { - let &Script(ref data) = self; - data.consensus_encode(s) - } + #[inline] + fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { + let &Script(ref data) = self; + data.consensus_encode(s) + } } impl ConsensusDecodable for Script { - #[inline] - fn consensus_decode(d: &mut D) -> Result { - Ok(Script(try!(ConsensusDecodable::consensus_decode(d)))) - } + #[inline] + fn consensus_decode(d: &mut D) -> Result { + Ok(Script(try!(ConsensusDecodable::consensus_decode(d)))) + } } #[cfg(test)] mod test { - use std::io::IoResult; - use serialize::hex::FromHex; + use std::io; + use serialize::hex::FromHex; - use super::{Script, build_scriptint, read_scriptint, read_scriptbool}; - use super::{EqualVerifyFailed, NoTransaction, PopEmptyStack}; - use super::MaybeOwned::Owned; + use super::{Error, Script, build_scriptint, read_scriptint, read_scriptbool}; + use super::MaybeOwned::Owned; - use network::serialize::{deserialize, serialize}; - use blockdata::opcodes; - use blockdata::transaction::Transaction; + 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 tx_hex = tx_hex.from_hex().unwrap(); + fn test_tx(tx_hex: &'static str, output_hex: Vec<&'static str>) { + let tx_hex = tx_hex.from_hex().unwrap(); - let tx: Transaction = deserialize(tx_hex.clone()).ok().expect("transaction"); - let script_pk: Vec