// Rust Bitcoin Library // Written in 2014 by // Andrew Poelstra // // To the extent possible under law, the author(s) have dedicated all // copyright and related and neighboring rights to this software to // the public domain worldwide. This software is distributed without // any warranty. // // You should have received a copy of the CC0 Public Domain Dedication // along with this software. // If not, see . // //! # Script //! //! Scripts define Bitcoin's digital signature scheme: a signature is formed //! from a script (the second half of which is defined by a coin to be spent, //! and the first half provided by the spending transaction), and is valid //! iff the script leaves `TRUE` on the stack after being evaluated. //! Bitcoin's script is a stack-based assembly language similar in spirit to //! Forth. //! //! This module provides the structures and functions needed to support scripts. //! use std::char::from_digit; use std::default::Default; use serialize::json; use serialize::hex::ToHex; use crypto::digest::Digest; use crypto::ripemd160::Ripemd160; use crypto::sha1::Sha1; use crypto::sha2::Sha256; use secp256k1::Secp256k1; use secp256k1::key::PublicKey; use blockdata::opcodes; use blockdata::opcodes::Opcode; use blockdata::opcodes::all as allops; use blockdata::transaction::{Transaction, TxIn}; use network::encodable::{ConsensusDecodable, ConsensusEncodable}; use network::serialize::{SimpleDecoder, SimpleEncoder, serialize}; use util::hash::Sha256dHash; use util::misc::script_find_and_remove; use util::thinvec::ThinVec; #[deriving(PartialEq, Eq, Show, Clone)] /// A Bitcoin script pub struct Script(ThinVec); /// Ways that a script might fail. Not everything is split up as /// much as it could be; patches welcome if more detailed errors /// would help you. #[deriving(PartialEq, Eq, Show, Clone)] pub enum ScriptError { /// OP_CHECKSIG was called with a bad public key BadPublicKey, /// OP_CHECKSIG was called with a bad signature BadSignature, /// An ECDSA error EcdsaError(::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, /// 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(int), /// A multisig tx with negative or too many signatures MultisigBadSigCount(int), /// 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, /// An OP_VERIFY happened with an empty stack VerifyEmptyStack, /// An OP_VERIFY happened with zero on the stack VerifyFailed, } impl json::ToJson for ScriptError { fn to_json(&self) -> json::Json { json::String(self.to_string()) } } /// A single iteration of a script execution #[deriving(PartialEq, Eq, Show, Clone)] pub struct TraceIteration { index: uint, opcode: allops::Opcode, executed: bool, effect: opcodes::OpcodeClass, stack: Vec } /// A full trace of a script execution #[deriving(PartialEq, Eq, Show, Clone)] pub struct ScriptTrace { /// A copy of the script pub script: Script, /// A copy of the script's initial stack, hex-encoded pub initial_stack: Vec, /// A list of iterations pub iterations: Vec, /// An error if one was returned, or None pub error: Option } impl_json!(TraceIteration, index, opcode, executed, effect, stack) /// Hashtype of a transaction, encoded in the last byte of a signature, /// specifically in the last 5 bits `byte & 31` #[deriving(PartialEq, Eq, Show, Clone)] pub enum SignatureHashType { /// 0x1: Sign all outputs SigHashAll, /// 0x2: Sign no outputs --- anyone can choose the destination SigHashNone, /// 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.) SigHashSingle, /// ???: Anything else is a non-canonical synonym for SigHashAll, for example /// zero appears a few times in the chain SigHashUnknown } impl SignatureHashType { /// Returns a SignatureHashType along with a boolean indicating whether /// the `ANYONECANPAY` flag is set, read from the last byte of a signature. fn from_signature(signature: &[u8]) -> (SignatureHashType, bool) { let byte = signature[signature.len() - 1]; let sighash = match byte & 0x1f { 1 => SigHashAll, 2 => SigHashNone, 3 => SigHashSingle, _ => SigHashUnknown }; (sighash, (byte & 0x80) != 0) } } /// A structure that can hold either a slice or vector, as necessary #[deriving(Clone, Show)] pub enum MaybeOwned<'a> { /// Freshly allocated memory Owned(Vec), /// Pointer into the original script Slice(&'a [u8]) } impl<'a> PartialEq for MaybeOwned<'a> { #[inline] fn eq(&self, other: &MaybeOwned) -> bool { self.as_slice() == other.as_slice() } } impl<'a> Eq for MaybeOwned<'a> {} impl<'a> Slice for MaybeOwned<'a> { #[inline] fn as_slice<'a>(&'a self) -> &'a [u8] { match *self { Owned(ref v) => v.as_slice(), Slice(ref s) => s.as_slice() } } } impl<'a> Collection for MaybeOwned<'a> { #[inline] fn len(&self) -> uint { match *self { Owned(ref v) => v.len(), Slice(ref s) => s.len() } } } static script_true: &'static [u8] = &[0x01]; static script_false: &'static [u8] = &[0x00]; /// Helper to encode an integer in script format fn build_scriptint(n: i64) -> Vec { if n == 0 { return vec![] } let neg = n < 0; let mut abs = if neg { -n } else { n } as uint; let mut v = vec![]; while abs > 0xFF { v.push((abs & 0xFF) as u8); abs >>= 8; } // If the number's value causes the sign bit to be set, we need an extra // byte to get the correct value and correct sign bit if abs & 0x80 != 0 { v.push(abs as u8); v.push(if neg { 0x80u8 } else { 0u8 }); } // Otherwise we just set the sign bit ourselves else { abs |= if neg { 0x80 } else { 0 }; v.push(abs as u8); } v } /// Helper to decode an integer in script format /// Notice that this fails on overflow: the result is the same as in /// bitcoind, that only 4-byte signed-magnitude values may be read as /// numbers. They can be added or subtracted (and a long time ago, /// multiplied and divided), and this may result in numbers which /// can't be written out in 4 bytes or less. This is ok! The number /// just can't be read as a number again. /// This is a bit crazy and subtle, but it makes sense: you can load /// 32-bit numbers and do anything with them, which back when mult/div /// was allowed, could result in up to a 64-bit number. We don't want /// overflow since that's suprising --- and we don't want numbers that /// don't fit in 64 bits (for efficiency on modern processors) so we /// simply say, anything in excess of 32 bits is no longer a number. /// This is basically a ranged type implementation. pub fn read_scriptint(v: &[u8]) -> Result { let len = v.len(); if len == 0 { return Ok(0); } if len > 4 { return Err(NumericOverflow); } let (mut ret, sh) = v.iter() .fold((0, 0), |(acc, sh), n| (acc + (*n as i64 << sh), sh + 8)); if v[len - 1] & 0x80 != 0 { ret &= (1 << sh - 1) - 1; ret = -ret; } Ok(ret) } /// This is like "read_scriptint then map 0 to false and everything /// else as true", except that the overflow rules don't apply. #[inline] pub fn read_scriptbool(v: &[u8]) -> bool { !v.iter().all(|&w| w == 0) } /// Read a script-encoded unsigned integer pub fn read_uint<'a, I:Iterator<&'a u8>>(mut iter: I, size: uint) -> Result { let mut ret = 0; for i in range(0, size) { match iter.next() { Some(&n) => ret += n as uint << (i * 8), None => { return Err(EarlyEndOfScript); } } } Ok(ret) } /// Check a signature -- returns an error that is currently just translated /// into a 0/1 to push onto the script stack fn check_signature(secp: &Secp256k1, sig_slice: &[u8], pk_slice: &[u8], script: Vec, tx: &Transaction, input_index: uint) -> Result<(), ScriptError> { // Check public key let pubkey = PublicKey::from_slice(pk_slice); if pubkey.is_err() { return Err(BadPublicKey); } let pubkey = pubkey.unwrap(); // Check signature and hashtype if sig_slice.len() == 0 { return Err(BadSignature); } let (hashtype, anyone_can_pay) = SignatureHashType::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(ThinVec::from_vec(script.take_unwrap())); tx_copy.input = vec![old_input]; } else { // Otherwise we keep all the inputs, blanking out the others and even // 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(ThinVec::from_vec(script.take_unwrap())); } else { new_input.script_sig = Script::new(); // If we aren't signing them, also zero out the sequence number if hashtype == SigHashSingle || hashtype == SigHashNone { new_input.sequence = 0; } } tx_copy.input.push(new_input); } } // Erase outputs as appropriate let mut sighash_single_bug = false; match hashtype { SigHashNone => { tx_copy.output = vec![]; } SigHashSingle => { if input_index < tx_copy.output.len() { let mut new_outs = Vec::with_capacity(input_index + 1); for _ in range(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; } } SigHashAll | SigHashUnknown => {} } 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.as_slice())).unwrap() }; secp.verify(signature_hash.as_slice(), sig_slice, &pubkey).map_err(|e| EcdsaError(e)) } // Macro to translate English stack instructions into Rust code. // All number are references to stack positions: 1 is the top, // 2 is the second-to-top, etc. The numbers do not change within // an opcode; to delete the top two items do `drop 1 drop 2` // rather than `drop 1 drop 1`, which will fail. // This is useful for only about a dozen opcodes, but those ones // were really hard to read and verify -- see OP_PICK and OP_ROLL // for an example of what Rust vector-stack manipulation looks // like. macro_rules! stack_opcode( ($stack:ident($min:expr): $(copy $c:expr)* $(swap ($a:expr, $b:expr))* $(perm ($first:expr $(->$i:expr)*) )* $(drop $d:expr)* ) => ({ // Record top let top = $stack.len(); // Check stack size if top < $min { return Err(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); )* }); ) macro_rules! stack_opcode_provable( ($stack:ident($min:expr): $(copy $c:expr)* $(swap ($a:expr, $b:expr))* $(perm ($first:expr $(->$i:expr)*) )* $(drop $d:expr)* ) => ({ // Record top let top = $stack.len(); // Do copies -- if we can't copy, and there is anything on the stack, return // "not unspendable" since we can no longer predict the top of the stack $( if top >= $c { let elem = $stack[top - $c].clone(); $stack.push(elem); } else if top > 0 { return false; } )* // Do swaps -- if we can't, return "not unspendable" $( if top >= $a && top >= $b { $stack.as_mut_slice().swap(top - $a, top - $b); } else if top > 0 { return false; } )* // Do permutations -- if we can't, return "not unspendable" if top >= $min { $( let first = $first; $( $stack.as_mut_slice().swap(top - first, top - $i); )* )* } else if top > 0 { return false; } // Do drops last so that dropped values will be available above $( if top >= $d { $stack.remove(top - $d); } )* }); ) /// Macro to translate numerical operations into stack ones macro_rules! num_opcode( ($stack:ident($($var:ident),*): $op:expr) => ({ $( let $var = try!(read_scriptint(match $stack.pop() { Some(elem) => elem, None => { return Err(PopEmptyStack); } }.as_slice())); )* $stack.push(Owned(build_scriptint($op))); // Return a tuple of all the variables ($( $var ),*) }); ) macro_rules! num_opcode_provable( ($stack:ident($($var:ident),*): $op:expr) => ({ let mut failed = false; $( let $var = match read_scriptint(match $stack.pop() { Some(elem) => elem, // Out of stack elems: fine, just don't push a new one None => { failed = true; Slice(script_false) } }.as_slice()) { Ok(n) => n, // Overflow is overflow, "provably unspendable" Err(_) => { return true; } }; )* if !failed { $stack.push(Owned(build_scriptint($op))); } }); ) /// Macro to translate hashing operations into stack ones macro_rules! hash_opcode( ($stack:ident, $hash:ident) => ({ match $stack.pop() { None => { return Err(PopEmptyStack); } Some(v) => { let mut engine = $hash::new(); engine.input(v.as_slice()); let mut ret = Vec::with_capacity(engine.output_bits() / 8); // Force-set the length even though the vector is uninitialized // This is OK only because u8 has no destructor unsafe { ret.set_len(engine.output_bits() / 8); } engine.result(ret.as_mut_slice()); $stack.push(Owned(ret)); } } }); ) macro_rules! hash_opcode_provable( ($stack:ident, $hash:ident) => ({ match $stack.pop() { None => { } Some(v) => { let mut engine = $hash::new(); engine.input(v.as_slice()); let mut ret = Vec::with_capacity(engine.output_bits() / 8); // Force-set the length even though the vector is uninitialized // This is OK only because u8 has no destructor unsafe { ret.set_len(engine.output_bits() / 8); } engine.result(ret.as_mut_slice()); $stack.push(Owned(ret)); } } }); ) // OP_VERIFY macro macro_rules! op_verify ( ($stack:expr, $err:expr) => ( match $stack.last().map(|v| read_scriptbool(v.as_slice())) { None => { return Err(VerifyEmptyStack); } Some(false) => { return Err($err); } Some(true) => { $stack.pop(); } } ) ) macro_rules! op_verify_provable ( ($stack:expr) => ( match $stack.last().map(|v| read_scriptbool(v.as_slice())) { None => { } Some(false) => { return true; } Some(true) => { $stack.pop(); } } ) ) impl Script { /// Creates a new empty script pub fn new() -> Script { Script(ThinVec::new()) } /// Creates a new script from an existing vector pub fn from_vec(v: Vec) -> Script { Script(ThinVec::from_vec(v)) } /// 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 + allops::OP_TRUE as u8); return; } // We can also special-case zero if data == 0 { let &Script(ref mut raw) = self; raw.push(allops::OP_FALSE as u8); return; } // 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).as_slice()); } /// 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::OP_PUSHDATA1 as uint => { raw.push(n as u8); }, n if n < 0x100 => { raw.push(opcodes::OP_PUSHDATA1 as u8); raw.push(n as u8); }, n if n < 0x10000 => { raw.push(opcodes::OP_PUSHDATA2 as u8); raw.push((n % 0x100) as u8); raw.push((n / 0x100) as u8); }, n if n < 0x100000000 => { raw.push(opcodes::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); } _ => fail!("tried to put a 4bn+ sized object into a script!") } // 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: allops::Opcode) { 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() } /// Trace a script pub fn trace<'a>(&'a self, stack: &mut Vec>, input_context: Option<(&Transaction, uint)>) -> ScriptTrace { let mut trace = ScriptTrace { script: self.clone(), initial_stack: stack.iter().map(|elem| elem.as_slice().to_hex()).collect(), iterations: vec![], error: None }; match self.evaluate(stack, input_context, Some(&mut trace.iterations)) { Ok(_) => {}, Err(e) => { trace.error = Some(e.clone()); } } trace } /// Evaluate the script, modifying the stack in place pub fn evaluate<'a>(&'a self, stack: &mut Vec>, input_context: Option<(&Transaction, uint)>, mut trace: Option<&mut Vec>) -> Result<(), ScriptError> { let &Script(ref raw) = self; let secp = Secp256k1::new(); let mut codeseparator_index = 0u; let mut exec_stack = vec![true]; let mut alt_stack = vec![]; let mut index = 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 = allops::Opcode::from_u8(byte); t.push(TraceIteration { index: index, opcode: opcode, executed: executing, effect: opcode.classify(), stack: vec![] }); } None => {} } index += 1; // The definitions of all these categories are in opcodes.rs //println!("read {} as {} as {} ... stack before op is {}", byte, allops::Opcode::from_u8(byte), allops::Opcode::from_u8(byte).classify(), stack); match (executing, allops::Opcode::from_u8(byte).classify()) { // Illegal operations mean failure regardless of execution state (_, opcodes::IllegalOp) => return Err(IllegalOpcode), // Push number (true, opcodes::PushNum(n)) => stack.push(Owned(build_scriptint(n as i64))), // Return operations mean failure, but only if executed (true, opcodes::ReturnOp) => return Err(ExecutedReturn), // Data-reading statements still need to read, even when not executing (_, opcodes::PushBytes(n)) => { if raw.len() < index + n { return Err(EarlyEndOfScript); } if executing { stack.push(Slice(raw.slice(index, index + n))); } index += n; } (_, opcodes::Ordinary(opcodes::OP_PUSHDATA1)) => { if raw.len() < index + 1 { return Err(EarlyEndOfScript); } let n = try!(read_uint(raw.slice_from(index).iter(), 1)); if raw.len() < index + 1 + n { return Err(EarlyEndOfScript); } if executing { stack.push(Slice(raw.slice(index + 1, index + n + 1))); } index += 1 + n; } (_, opcodes::Ordinary(opcodes::OP_PUSHDATA2)) => { if raw.len() < index + 2 { return Err(EarlyEndOfScript); } let n = try!(read_uint(raw.slice_from(index).iter(), 2)); if raw.len() < index + 2 + n { return Err(EarlyEndOfScript); } if executing { stack.push(Slice(raw.slice(index + 2, index + n + 2))); } index += 2 + n; } (_, opcodes::Ordinary(opcodes::OP_PUSHDATA4)) => { if raw.len() < index + 4 { return Err(EarlyEndOfScript); } let n = try!(read_uint(raw.slice_from(index).iter(), 4)); if raw.len() < index + 4 + n { return Err(EarlyEndOfScript); } if executing { stack.push(Slice(raw.slice(index + 4, index + n + 4))); } index += 4 + n; } // If-statements take effect when not executing (false, opcodes::Ordinary(opcodes::OP_IF)) => exec_stack.push(false), (false, opcodes::Ordinary(opcodes::OP_NOTIF)) => exec_stack.push(false), (false, opcodes::Ordinary(opcodes::OP_ELSE)) => { match exec_stack.mut_last() { Some(ref_e) => { *ref_e = !*ref_e } None => { return Err(ElseWithoutIf); } } } (false, opcodes::Ordinary(opcodes::OP_ENDIF)) => { if exec_stack.pop().is_none() { return Err(EndifWithoutIf); } } // No-ops and non-executed operations do nothing (true, opcodes::NoOp) | (false, _) => {} // Actual opcodes (true, opcodes::Ordinary(op)) => { match op { opcodes::OP_PUSHDATA1 | opcodes::OP_PUSHDATA2 | opcodes::OP_PUSHDATA4 => { // handled above } opcodes::OP_IF => { match stack.pop().map(|v| read_scriptbool(v.as_slice())) { None => { return Err(IfEmptyStack); } Some(b) => exec_stack.push(b) } } opcodes::OP_NOTIF => { match stack.pop().map(|v| read_scriptbool(v.as_slice())) { None => { return Err(IfEmptyStack); } Some(b) => exec_stack.push(!b), } } opcodes::OP_ELSE => { match exec_stack.mut_last() { Some(ref_e) => { *ref_e = !*ref_e } None => { return Err(ElseWithoutIf); } } } opcodes::OP_ENDIF => { if exec_stack.pop().is_none() { return Err(EndifWithoutIf); } } opcodes::OP_VERIFY => op_verify!(stack, VerifyFailed), opcodes::OP_TOALTSTACK => { match stack.pop() { None => { return Err(PopEmptyStack); } Some(elem) => { alt_stack.push(elem); } } } opcodes::OP_FROMALTSTACK => { match alt_stack.pop() { None => { return Err(PopEmptyStack); } Some(elem) => { stack.push(elem); } } } opcodes::OP_2DROP => stack_opcode!(stack(2): drop 1 drop 2), opcodes::OP_2DUP => stack_opcode!(stack(2): copy 2 copy 1), opcodes::OP_3DUP => stack_opcode!(stack(3): copy 3 copy 2 copy 1), opcodes::OP_2OVER => stack_opcode!(stack(4): copy 4 copy 3), opcodes::OP_2ROT => stack_opcode!(stack(6): perm (1 -> 3 -> 5) perm (2 -> 4 -> 6)), opcodes::OP_2SWAP => stack_opcode!(stack(4): swap (2, 4) swap (1, 3)), opcodes::OP_DROP => stack_opcode!(stack(1): drop 1), opcodes::OP_DUP => stack_opcode!(stack(1): copy 1), opcodes::OP_NIP => stack_opcode!(stack(2): drop 2), opcodes::OP_OVER => stack_opcode!(stack(2): copy 2), opcodes::OP_PICK => { let n = match stack.pop() { Some(data) => try!(read_scriptint(data.as_slice())), None => { return Err(PopEmptyStack); } }; if n < 0 { return Err(NegativePick); } let n = n as uint; stack_opcode!(stack(n + 1): copy n + 1) } opcodes::OP_ROLL => { let n = match stack.pop() { Some(data) => try!(read_scriptint(data.as_slice())), None => { return Err(PopEmptyStack); } }; if n < 0 { return Err(NegativeRoll); } let n = n as uint; stack_opcode!(stack(n + 1): copy n + 1 drop n + 1) } opcodes::OP_ROT => stack_opcode!(stack(3): perm (1 -> 2 -> 3)), opcodes::OP_SWAP => stack_opcode!(stack(2): swap (1, 2)), opcodes::OP_TUCK => stack_opcode!(stack(2): copy 2 copy 1 drop 2), opcodes::OP_IFDUP => { match stack.last().map(|v| read_scriptbool(v.as_slice())) { None => { return Err(IfEmptyStack); } Some(false) => {} Some(true) => { stack_opcode!(stack(1): copy 1); } } } opcodes::OP_DEPTH => { let len = stack.len() as i64; stack.push(Owned(build_scriptint(len))); } opcodes::OP_SIZE => { match stack.last().map(|v| v.len() as i64) { None => { return Err(IfEmptyStack); } Some(n) => { stack.push(Owned(build_scriptint(n))); } } } opcodes::OP_EQUAL | opcodes::OP_EQUALVERIFY => { if stack.len() < 2 { return Err(PopEmptyStack); } let a = stack.pop().unwrap(); let b = stack.pop().unwrap(); stack.push(Slice(if a == b { script_true } else { script_false })); if op == opcodes::OP_EQUALVERIFY { op_verify!(stack, EqualVerifyFailed(a.as_slice().to_hex(), b.as_slice().to_hex())); } } opcodes::OP_1ADD => { num_opcode!(stack(a): a + 1); } opcodes::OP_1SUB => { num_opcode!(stack(a): a - 1); } opcodes::OP_NEGATE => { num_opcode!(stack(a): -a); } opcodes::OP_ABS => { num_opcode!(stack(a): a.abs()); } opcodes::OP_NOT => { num_opcode!(stack(a): if a == 0 {1} else {0}); } opcodes::OP_0NOTEQUAL => { num_opcode!(stack(a): if a != 0 {1} else {0}); } opcodes::OP_ADD => { num_opcode!(stack(b, a): a + b); } opcodes::OP_SUB => { num_opcode!(stack(b, a): a - b); } opcodes::OP_BOOLAND => { num_opcode!(stack(b, a): if a != 0 && b != 0 {1} else {0}); } opcodes::OP_BOOLOR => { num_opcode!(stack(b, a): if a != 0 || b != 0 {1} else {0}); } opcodes::OP_NUMEQUAL => { num_opcode!(stack(b, a): if a == b {1} else {0}); } opcodes::OP_NUMNOTEQUAL => { num_opcode!(stack(b, a): if a != b {1} else {0}); } opcodes::OP_NUMEQUALVERIFY => { let (b, a) = num_opcode!(stack(b, a): if a == b {1} else {0}); op_verify!(stack, NumEqualVerifyFailed(a, b)); } opcodes::OP_LESSTHAN => { num_opcode!(stack(b, a): if a < b {1} else {0}); } opcodes::OP_GREATERTHAN => { num_opcode!(stack(b, a): if a > b {1} else {0}); } opcodes::OP_LESSTHANOREQUAL => { num_opcode!(stack(b, a): if a <= b {1} else {0}); } opcodes::OP_GREATERTHANOREQUAL => { num_opcode!(stack(b, a): if a >= b {1} else {0}); } opcodes::OP_MIN => { num_opcode!(stack(b, a): if a < b {a} else {b}); } opcodes::OP_MAX => { num_opcode!(stack(b, a): if a > b {a} else {b}); } opcodes::OP_WITHIN => { num_opcode!(stack(c, b, a): if b <= a && a < c {1} else {0}); } opcodes::OP_RIPEMD160 => hash_opcode!(stack, Ripemd160), opcodes::OP_SHA1 => hash_opcode!(stack, Sha1), opcodes::OP_SHA256 => hash_opcode!(stack, Sha256), opcodes::OP_HASH160 => { hash_opcode!(stack, Sha256); hash_opcode!(stack, Ripemd160); } opcodes::OP_HASH256 => { hash_opcode!(stack, Sha256); hash_opcode!(stack, Sha256); } opcodes::OP_CODESEPARATOR => { codeseparator_index = index; } opcodes::OP_CHECKSIG | opcodes::OP_CHECKSIGVERIFY => { if stack.len() < 2 { return Err(PopEmptyStack); } let pk = stack.pop().unwrap(); let pk_slice = pk.as_slice(); let sig = stack.pop().unwrap(); let sig_slice = sig.as_slice(); // Compute the section of script that needs to be hashed: everything // from the last CODESEPARATOR, except the signature itself. let mut script = Vec::from_slice(raw.slice_from(codeseparator_index)); let mut remove = Script::new(); remove.push_slice(sig_slice); script_find_and_remove(&mut script, remove.as_slice()); script_find_and_remove(&mut script, [opcodes::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(NoTransaction); } // Otherwise unwrap it let (tx, input_index) = input_context.unwrap(); match check_signature(&secp, sig_slice, pk_slice, script, tx, input_index) { Ok(()) => stack.push(Slice(script_true)), _ => stack.push(Slice(script_false)), } if op == opcodes::OP_CHECKSIGVERIFY { op_verify!(stack, VerifyFailed); } } opcodes::OP_CHECKMULTISIG | opcodes::OP_CHECKMULTISIGVERIFY => { // Read all the keys if stack.len() < 1 { return Err(PopEmptyStack); } let n_keys = try!(read_scriptint(stack.pop().unwrap().as_slice())); if n_keys < 0 || n_keys > 20 { return Err(MultisigBadKeyCount(n_keys as int)); } if (stack.len() as i64) < n_keys { return Err(PopEmptyStack); } let mut keys = Vec::with_capacity(n_keys as uint); for _ in range(0, n_keys) { keys.push(stack.pop().unwrap()); } // Read all the signatures if stack.len() < 1 { return Err(PopEmptyStack); } let n_sigs = try!(read_scriptint(stack.pop().unwrap().as_slice())); if n_sigs < 0 || n_sigs > n_keys { return Err(MultisigBadSigCount(n_sigs as int)); } if (stack.len() as i64) < n_sigs { return Err(PopEmptyStack); } let mut sigs = Vec::with_capacity(n_sigs as uint); for _ in range(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(PopEmptyStack); } // Compute the section of script that needs to be hashed: everything // from the last CODESEPARATOR, except the signatures themselves. let mut script = Vec::from_slice(raw.slice_from(codeseparator_index)); for sig in sigs.iter() { let mut remove = Script::new(); remove.push_slice(sig.as_slice()); script_find_and_remove(&mut script, remove.as_slice()); script_find_and_remove(&mut script, [opcodes::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(NoTransaction); } // Otherwise unwrap it let (tx, input_index) = input_context.unwrap(); // Check signatures let mut key_iter = keys.iter(); let mut sig_iter = sigs.iter(); let mut key = key_iter.next(); let mut sig = sig_iter.next(); loop { match (key, sig) { // Try to validate the signature with the given key (Some(k), Some(s)) => { // Move to the next signature if it is valid for the current key if check_signature(&secp, s.as_slice(), k.as_slice(), 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(Slice(script_true)); break; } // Run out of keys to match to signatures, fail (None, Some(_)) => { stack.push(Slice(script_false)); break; } } } if op == opcodes::OP_CHECKMULTISIGVERIFY { op_verify!(stack, VerifyFailed); } } } // end opcode match } // end classification match } // end loop // Store the stack in the trace trace.as_mut().map(|t| t.mut_last().map(|t| t.stack = stack.iter().map(|elem| elem.as_slice().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) == allops::OP_HASH160 as u8 && *raw.get(1) == allops::OP_PUSHBYTES_20 as u8 && *raw.get(22) == allops::OP_EQUAL as u8 } } /// Evaluate the script to determine whether any possible input will cause it /// to accept. Returns true if it is guaranteed to fail; false otherwise. pub fn is_provably_unspendable(&self) -> bool { let &Script(ref raw) = self; fn recurse<'a>(script: &'a [u8], mut stack: Vec>, depth: uint) -> bool { let mut exec_stack = vec![true]; let mut alt_stack = vec![]; // Avoid doing more than 64k forks if depth > 16 { return false; } let mut index = 0; while index < script.len() { let executing = exec_stack.iter().all(|e| *e); let byte = script[index]; index += 1; // The definitions of all these categories are in opcodes.rs //println!("read {} as {} as {} ... stack before op is {}", byte, allops::Opcode::from_u8(byte), allops::Opcode::from_u8(byte).classify(), stack); match (executing, allops::Opcode::from_u8(byte).classify()) { // Illegal operations mean failure regardless of execution state (_, opcodes::IllegalOp) => { return true; } // Push number (true, opcodes::PushNum(n)) => stack.push(Owned(build_scriptint(n as i64))), // Return operations mean failure, but only if executed (true, opcodes::ReturnOp) => { return true; } // Data-reading statements still need to read, even when not executing (_, opcodes::PushBytes(n)) => { if script.len() < index + n { return true; } if executing { stack.push(Slice(script.slice(index, index + n))); } index += n; } (_, opcodes::Ordinary(opcodes::OP_PUSHDATA1)) => { if script.len() < index + 1 { return true; } let n = match read_uint(script.slice_from(index).iter(), 1) { Ok(n) => n, Err(_) => { return true; } }; if script.len() < index + 1 + n { return true; } if executing { stack.push(Slice(script.slice(index + 1, index + n + 1))); } index += 1 + n; } (_, opcodes::Ordinary(opcodes::OP_PUSHDATA2)) => { if script.len() < index + 2 { return true; } let n = match read_uint(script.slice_from(index).iter(), 2) { Ok(n) => n, Err(_) => { return true; } }; if script.len() < index + 2 + n { return true; } if executing { stack.push(Slice(script.slice(index + 2, index + n + 2))); } index += 2 + n; } (_, opcodes::Ordinary(opcodes::OP_PUSHDATA4)) => { let n = match read_uint(script.slice_from(index).iter(), 4) { Ok(n) => n, Err(_) => { return true; } }; if script.len() < index + 4 + n { return true; } if executing { stack.push(Slice(script.slice(index + 4, index + n + 4))); } index += 4 + n; } // If-statements take effect when not executing (false, opcodes::Ordinary(opcodes::OP_IF)) => exec_stack.push(false), (false, opcodes::Ordinary(opcodes::OP_NOTIF)) => exec_stack.push(false), (false, opcodes::Ordinary(opcodes::OP_ELSE)) => { match exec_stack.mut_last() { Some(ref_e) => { *ref_e = !*ref_e } None => { return true; } } } (false, opcodes::Ordinary(opcodes::OP_ENDIF)) => { if exec_stack.pop().is_none() { return true; } } // No-ops and non-executed operations do nothing (true, opcodes::NoOp) | (false, _) => {} // Actual opcodes (true, opcodes::Ordinary(op)) => { match op { opcodes::OP_PUSHDATA1 | opcodes::OP_PUSHDATA2 | opcodes::OP_PUSHDATA4 => { // handled above } opcodes::OP_IF => { match stack.pop().map(|v| read_scriptbool(v.as_slice())) { None => { let mut stack_true = stack.clone(); stack_true.push(Slice(script_true)); stack.push(Slice(script_false)); return recurse(script.slice_from(index - 1), stack, depth + 1) && recurse(script.slice_from(index - 1), stack_true, depth + 1); } Some(b) => exec_stack.push(b) } } opcodes::OP_NOTIF => { match stack.pop().map(|v| read_scriptbool(v.as_slice())) { None => { let mut stack_true = stack.clone(); stack_true.push(Slice(script_true)); stack.push(Slice(script_false)); return recurse(script.slice_from(index - 1), stack, depth + 1) && recurse(script.slice_from(index - 1), stack_true, depth + 1); } Some(b) => exec_stack.push(!b), } } opcodes::OP_ELSE => { match exec_stack.mut_last() { Some(ref_e) => { *ref_e = !*ref_e } None => { return true; } } } opcodes::OP_ENDIF => { if exec_stack.pop().is_none() { return true; } } opcodes::OP_VERIFY => op_verify_provable!(stack), opcodes::OP_TOALTSTACK => { stack.pop().map(|elem| alt_stack.push(elem)); } opcodes::OP_FROMALTSTACK => { alt_stack.pop().map(|elem| stack.push(elem)); } opcodes::OP_2DROP => stack_opcode_provable!(stack(2): drop 1 drop 2), opcodes::OP_2DUP => stack_opcode_provable!(stack(2): copy 2 copy 1), opcodes::OP_3DUP => stack_opcode_provable!(stack(3): copy 3 copy 2 copy 1), opcodes::OP_2OVER => stack_opcode_provable!(stack(4): copy 4 copy 3), opcodes::OP_2ROT => stack_opcode_provable!(stack(6): perm (1 -> 3 -> 5) perm (2 -> 4 -> 6)), opcodes::OP_2SWAP => stack_opcode_provable!(stack(4): swap (2, 4) swap (1, 3)), opcodes::OP_DROP => stack_opcode_provable!(stack(1): drop 1), opcodes::OP_DUP => stack_opcode_provable!(stack(1): copy 1), opcodes::OP_NIP => stack_opcode_provable!(stack(2): drop 2), opcodes::OP_OVER => stack_opcode_provable!(stack(2): copy 2), opcodes::OP_PICK => { let n = match stack.pop() { Some(data) => match read_scriptint(data.as_slice()) { Ok(n) => n, Err(_) => { return true; } }, None => { return false; } }; if n < 0 { return true; } let n = n as uint; stack_opcode_provable!(stack(n + 1): copy n + 1) } opcodes::OP_ROLL => { let n = match stack.pop() { Some(data) => match read_scriptint(data.as_slice()) { Ok(n) => n, Err(_) => { return true; } }, None => { return false; } }; if n < 0 { return true; } let n = n as uint; stack_opcode_provable!(stack(n + 1): copy n + 1 drop n + 1) } opcodes::OP_ROT => stack_opcode_provable!(stack(3): perm (1 -> 2 -> 3)), opcodes::OP_SWAP => stack_opcode_provable!(stack(2): swap (1, 2)), opcodes::OP_TUCK => stack_opcode_provable!(stack(2): copy 2 copy 1 drop 2), opcodes::OP_IFDUP => { match stack.last().map(|v| read_scriptbool(v.as_slice())) { None => { let mut stack_true = stack.clone(); stack_true.push(Slice(script_true)); stack.push(Slice(script_false)); return recurse(script.slice_from(index - 1), stack, depth + 1) && recurse(script.slice_from(index - 1), stack_true, depth + 1); } Some(false) => {} Some(true) => { stack_opcode_provable!(stack(1): copy 1); } } } // Not clear what we can meaningfully do with these (I guess add an // `Unknown` variant to `MaybeOwned` and change all the code to deal // with it), and they aren't common, so just say "not unspendable". opcodes::OP_DEPTH | opcodes::OP_SIZE => { return false; } opcodes::OP_EQUAL | opcodes::OP_EQUALVERIFY => { if stack.len() < 2 { stack.pop(); stack.pop(); let mut stack_true = stack.clone(); if op == opcodes::OP_EQUALVERIFY { return recurse(script.slice_from(index), stack, depth + 1); } else { stack_true.push(Slice(script_true)); stack.push(Slice(script_false)); return recurse(script.slice_from(index), stack, depth + 1) && recurse(script.slice_from(index), stack_true, depth + 1); } } let a = stack.pop().unwrap(); let b = stack.pop().unwrap(); stack.push(Slice(if a == b { script_true } else { script_false })); if op == opcodes::OP_EQUALVERIFY { op_verify_provable!(stack); } } opcodes::OP_1ADD => num_opcode_provable!(stack(a): a + 1), opcodes::OP_1SUB => num_opcode_provable!(stack(a): a - 1), opcodes::OP_NEGATE => num_opcode_provable!(stack(a): -a), opcodes::OP_ABS => num_opcode_provable!(stack(a): a.abs()), opcodes::OP_NOT => num_opcode_provable!(stack(a): if a == 0 {1} else {0}), opcodes::OP_0NOTEQUAL => num_opcode_provable!(stack(a): if a != 0 {1} else {0}), opcodes::OP_ADD => num_opcode_provable!(stack(b, a): a + b), opcodes::OP_SUB => num_opcode_provable!(stack(b, a): a - b), opcodes::OP_BOOLAND => num_opcode_provable!(stack(b, a): if a != 0 && b != 0 {1} else {0}), opcodes::OP_BOOLOR => num_opcode_provable!(stack(b, a): if a != 0 || b != 0 {1} else {0}), opcodes::OP_NUMEQUAL => num_opcode_provable!(stack(b, a): if a == b {1} else {0}), opcodes::OP_NUMNOTEQUAL => num_opcode_provable!(stack(b, a): if a != b {1} else {0}), opcodes::OP_NUMEQUALVERIFY => { num_opcode_provable!(stack(b, a): if a == b {1} else {0}); op_verify_provable!(stack); } opcodes::OP_LESSTHAN => num_opcode_provable!(stack(b, a): if a < b {1} else {0}), opcodes::OP_GREATERTHAN => num_opcode_provable!(stack(b, a): if a > b {1} else {0}), opcodes::OP_LESSTHANOREQUAL => num_opcode_provable!(stack(b, a): if a <= b {1} else {0}), opcodes::OP_GREATERTHANOREQUAL => num_opcode_provable!(stack(b, a): if a >= b {1} else {0}), opcodes::OP_MIN => num_opcode_provable!(stack(b, a): if a < b {a} else {b}), opcodes::OP_MAX => num_opcode_provable!(stack(b, a): if a > b {a} else {b}), opcodes::OP_WITHIN => num_opcode_provable!(stack(c, b, a): if b <= a && a < c {1} else {0}), opcodes::OP_RIPEMD160 => hash_opcode_provable!(stack, Ripemd160), opcodes::OP_SHA1 => hash_opcode_provable!(stack, Sha1), opcodes::OP_SHA256 => hash_opcode_provable!(stack, Sha256), opcodes::OP_HASH160 => { hash_opcode_provable!(stack, Sha256); hash_opcode_provable!(stack, Ripemd160); } opcodes::OP_HASH256 => { hash_opcode_provable!(stack, Sha256); hash_opcode_provable!(stack, Sha256); } // Ignore code separators since we won't check signatures opcodes::OP_CODESEPARATOR => {} opcodes::OP_CHECKSIG | opcodes::OP_CHECKSIGVERIFY => { stack.pop(); stack.pop(); // If it's a VERIFY op, assume it passed and carry on if op != opcodes::OP_CHECKSIGVERIFY { let mut stack_true = stack.clone(); stack_true.push(Slice(script_true)); stack.push(Slice(script_false)); return recurse(script.slice_from(index), stack, depth + 1) && recurse(script.slice_from(index), stack_true, depth + 1); } } opcodes::OP_CHECKMULTISIG | opcodes::OP_CHECKMULTISIGVERIFY => { // Read all the keys if stack.len() >= 1 { let n_keys = match read_scriptint(stack.pop().unwrap().as_slice()) { Ok(n) => n, Err(_) => { return true; } }; if n_keys < 0 || n_keys > 20 { return true; } for _ in range(0, n_keys) { stack.pop(); } // Read all the signatures if stack.len() >= 1 { let n_sigs = match read_scriptint(stack.pop().unwrap().as_slice()) { Ok(n) => n, Err(_) => { return true; } }; if n_sigs < 0 || n_sigs > n_keys { return true; } for _ in range(0, n_sigs) { stack.pop(); } } } // Pop one more element off the stack to be replicate a consensus bug stack.pop(); // If it's a VERIFY op, assume it passed and carry on if op != opcodes::OP_CHECKSIGVERIFY { let mut stack_true = stack.clone(); stack_true.push(Slice(script_true)); stack.push(Slice(script_false)); return recurse(script.slice_from(index), stack, depth + 1) && recurse(script.slice_from(index), stack_true, depth + 1); } } } } } } // If we finished, we are only unspendable if we have false on the stack stack.last().is_some() && !read_scriptbool(stack.last().unwrap().as_slice()) } recurse(raw.as_slice(), vec![], 1) } } impl Default for Script { fn default() -> Script { Script(ThinVec::new()) } } // User-facing serialization impl json::ToJson for Script { // TODO: put this in a struct alongside an opcode decode fn to_json(&self) -> json::Json { let &Script(ref raw) = self; let mut ret = String::new(); for dat in raw.iter() { ret.push_char(from_digit((dat / 0x10) as uint, 16).unwrap()); ret.push_char(from_digit((dat & 0x0f) as uint, 16).unwrap()); } json::String(ret) } } // Network serialization impl, E> ConsensusEncodable for Script { #[inline] fn consensus_encode(&self, s: &mut S) -> Result<(), E> { let &Script(ref data) = self; data.consensus_encode(s) } } impl, E> ConsensusDecodable for Script { #[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 super::{Script, build_scriptint, read_scriptint, read_scriptbool}; use super::{EqualVerifyFailed, NoTransaction, PopEmptyStack}; use super::Owned; use network::serialize::{deserialize, serialize}; use blockdata::opcodes; use blockdata::transaction::Transaction; use util::thinvec::ThinVec; 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