2016-09-14 10:47:58 -07:00
|
|
|
use std::{cmp, mem};
|
2016-09-18 09:12:45 -07:00
|
|
|
use primitives::Bytes;
|
2016-09-14 03:54:32 -07:00
|
|
|
use keys::{Signature, Public};
|
2016-09-18 09:12:45 -07:00
|
|
|
use chain::SEQUENCE_LOCKTIME_DISABLE_FLAG;
|
2016-09-09 01:49:08 -07:00
|
|
|
use crypto::{sha1, sha256, dhash160, dhash256, ripemd160};
|
2016-09-14 03:54:32 -07:00
|
|
|
use script::{
|
2016-09-15 02:45:31 -07:00
|
|
|
script, Script, Num, VerificationFlags, Opcode, Error,
|
2016-09-17 06:46:53 -07:00
|
|
|
Sighash, SignatureChecker, SignatureVersion, Stack
|
2016-09-14 03:54:32 -07:00
|
|
|
};
|
2016-08-19 06:40:32 -07:00
|
|
|
|
2016-09-14 03:54:32 -07:00
|
|
|
/// Helper function.
|
|
|
|
fn check_signature(
|
|
|
|
checker: &SignatureChecker,
|
2016-09-14 08:48:00 -07:00
|
|
|
mut script_sig: Vec<u8>,
|
2016-09-14 03:54:32 -07:00
|
|
|
public: Vec<u8>,
|
|
|
|
script_code: &Script,
|
|
|
|
version: SignatureVersion
|
|
|
|
) -> bool {
|
|
|
|
let public = match Public::from_slice(&public) {
|
|
|
|
Ok(public) => public,
|
|
|
|
_ => return false,
|
|
|
|
};
|
2016-09-11 03:22:25 -07:00
|
|
|
|
2016-09-14 03:54:32 -07:00
|
|
|
if script_sig.is_empty() {
|
|
|
|
return false;
|
2016-09-07 07:15:07 -07:00
|
|
|
}
|
|
|
|
|
2016-09-14 08:48:00 -07:00
|
|
|
let hash_type = script_sig.pop().unwrap() as u32;
|
|
|
|
let signature = script_sig.into();
|
2016-09-07 07:15:07 -07:00
|
|
|
|
2016-09-14 03:54:32 -07:00
|
|
|
checker.check_signature(&signature, &public, script_code, hash_type, version)
|
2016-08-19 06:40:32 -07:00
|
|
|
}
|
|
|
|
|
2016-08-22 09:23:32 -07:00
|
|
|
fn is_public_key(v: &[u8]) -> bool {
|
|
|
|
match v.len() {
|
|
|
|
33 if v[0] == 2 || v[0] == 3 => true,
|
|
|
|
65 if v[0] == 4 => true,
|
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A canonical signature exists of: <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype>
|
|
|
|
/// Where R and S are not negative (their first byte has its highest bit not set), and not
|
|
|
|
/// excessively padded (do not start with a 0 byte, unless an otherwise negative number follows,
|
|
|
|
/// in which case a single 0 byte is necessary and even required).
|
|
|
|
///
|
|
|
|
/// See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623
|
|
|
|
///
|
|
|
|
/// This function is consensus-critical since BIP66.
|
|
|
|
fn is_valid_signature_encoding(sig: &[u8]) -> bool {
|
|
|
|
// Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] [sighash]
|
|
|
|
// * total-length: 1-byte length descriptor of everything that follows,
|
|
|
|
// excluding the sighash byte.
|
|
|
|
// * R-length: 1-byte length descriptor of the R value that follows.
|
|
|
|
// * R: arbitrary-length big-endian encoded R value. It must use the shortest
|
|
|
|
// possible encoding for a positive integers (which means no null bytes at
|
|
|
|
// the start, except a single one when the next byte has its highest bit set).
|
|
|
|
// * S-length: 1-byte length descriptor of the S value that follows.
|
|
|
|
// * S: arbitrary-length big-endian encoded S value. The same rules apply.
|
|
|
|
// * sighash: 1-byte value indicating what data is hashed (not part of the DER
|
|
|
|
// signature)
|
|
|
|
|
|
|
|
// Minimum and maximum size constraints
|
|
|
|
if sig.len() < 9 || sig.len() > 73 {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// A signature is of type 0x30 (compound)
|
|
|
|
if sig[0] != 0x30 {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure the length covers the entire signature.
|
|
|
|
if sig[1] as usize != sig.len() - 3 {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Extract the length of the R element.
|
|
|
|
let len_r = sig[3] as usize;
|
|
|
|
|
|
|
|
// Make sure the length of the S element is still inside the signature.
|
|
|
|
if len_r + 5 >= sig.len() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Extract the length of the S element.
|
|
|
|
let len_s = sig[len_r + 5] as usize;
|
|
|
|
|
|
|
|
// Verify that the length of the signature matches the sum of the length
|
|
|
|
if len_r + len_s + 7 != sig.len() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check whether the R element is an integer.
|
|
|
|
if sig[2] != 2 {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Zero-length integers are not allowed for R.
|
|
|
|
if len_r == 0 {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Negative numbers are not allowed for R.
|
|
|
|
if (sig[4] & 0x80) != 0 {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Null bytes at the start of R are not allowed, unless R would
|
|
|
|
// otherwise be interpreted as a negative number.
|
|
|
|
if len_r > 1 && sig[4] == 0 && (!(sig[5] & 0x80)) != 0 {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check whether the S element is an integer.
|
|
|
|
if sig[len_r + 4] != 2 {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Zero-length integers are not allowed for S.
|
|
|
|
if len_s == 0 {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Negative numbers are not allowed for S.
|
|
|
|
if (sig[len_r + 6] & 0x80) != 0 {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Null bytes at the start of S are not allowed, unless S would otherwise be
|
|
|
|
// interpreted as a negative number.
|
|
|
|
if len_s > 1 && (sig[len_r + 6] == 0) && (!(sig[len_r + 7] & 0x80)) != 0 {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
2016-09-11 03:22:25 -07:00
|
|
|
fn is_low_der_signature(sig: &[u8]) -> Result<(), Error> {
|
2016-08-22 09:23:32 -07:00
|
|
|
if !is_valid_signature_encoding(sig) {
|
|
|
|
return Err(Error::SignatureDer);
|
|
|
|
}
|
|
|
|
|
|
|
|
let signature: Signature = sig.into();
|
|
|
|
if !signature.check_low_s() {
|
|
|
|
return Err(Error::SignatureHighS);
|
|
|
|
}
|
|
|
|
|
2016-09-11 03:22:25 -07:00
|
|
|
Ok(())
|
2016-08-22 09:23:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn is_defined_hashtype_signature(sig: &[u8]) -> bool {
|
|
|
|
if sig.is_empty() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-09-14 03:54:32 -07:00
|
|
|
Sighash::is_defined(sig[sig.len() -1] as u32)
|
2016-08-22 09:23:32 -07:00
|
|
|
}
|
|
|
|
|
2016-09-11 03:22:25 -07:00
|
|
|
fn check_signature_encoding(sig: &[u8], flags: &VerificationFlags) -> Result<(), Error> {
|
2016-08-22 09:23:32 -07:00
|
|
|
// Empty signature. Not strictly DER encoded, but allowed to provide a
|
|
|
|
// compact way to provide an invalid signature for use with CHECK(MULTI)SIG
|
|
|
|
|
|
|
|
if sig.is_empty() {
|
2016-09-11 03:22:25 -07:00
|
|
|
return Ok(());
|
2016-08-22 09:23:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (flags.verify_dersig || flags.verify_low_s || flags.verify_strictenc) && !is_valid_signature_encoding(sig) {
|
2016-09-11 03:22:25 -07:00
|
|
|
return Err(Error::SignatureDer);
|
|
|
|
}
|
|
|
|
|
|
|
|
if flags.verify_low_s {
|
|
|
|
try!(is_low_der_signature(sig));
|
|
|
|
}
|
|
|
|
|
|
|
|
if flags.verify_strictenc && !is_defined_hashtype_signature(sig) {
|
2016-08-22 09:23:32 -07:00
|
|
|
Err(Error::SignatureHashtype)
|
|
|
|
} else {
|
2016-09-11 03:22:25 -07:00
|
|
|
Ok(())
|
2016-08-22 09:23:32 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-11 03:22:25 -07:00
|
|
|
fn check_pubkey_encoding(v: &[u8], flags: &VerificationFlags) -> Result<(), Error> {
|
2016-08-22 09:23:32 -07:00
|
|
|
if flags.verify_strictenc && !is_public_key(v) {
|
|
|
|
return Err(Error::PubkeyType);
|
|
|
|
}
|
|
|
|
|
2016-09-11 03:22:25 -07:00
|
|
|
Ok(())
|
2016-08-22 09:23:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn check_minimal_push(data: &[u8], opcode: Opcode) -> bool {
|
|
|
|
if data.is_empty() {
|
|
|
|
// Could have used OP_0.
|
|
|
|
opcode == Opcode::OP_0
|
|
|
|
} else if data.len() == 1 && data[0] >= 1 && data[0] <= 16 {
|
|
|
|
// Could have used OP_1 .. OP_16.
|
|
|
|
opcode as u8 == Opcode::OP_1 as u8 + (data[0] - 1)
|
|
|
|
} else if data.len() == 1 && data[0] == 0x81 {
|
|
|
|
// Could have used OP_1NEGATE
|
|
|
|
opcode == Opcode::OP_1NEGATE
|
|
|
|
} else if data.len() <= 75 {
|
|
|
|
// Could have used a direct push (opcode indicating number of bytes pushed + those bytes).
|
|
|
|
opcode as usize == data.len()
|
|
|
|
} else if data.len() <= 255 {
|
|
|
|
// Could have used OP_PUSHDATA.
|
|
|
|
opcode == Opcode::OP_PUSHDATA1
|
|
|
|
} else if data.len() <= 65535 {
|
|
|
|
// Could have used OP_PUSHDATA2.
|
|
|
|
opcode == Opcode::OP_PUSHDATA2
|
|
|
|
} else {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-08 06:05:57 -07:00
|
|
|
fn cast_to_bool(data: &[u8]) -> bool {
|
|
|
|
if data.is_empty() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if data[..data.len() - 1].iter().any(|x| x != &0) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
let last = data[data.len() - 1];
|
|
|
|
if last == 0 || last == 0x80 {
|
|
|
|
false
|
|
|
|
} else {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-14 10:47:58 -07:00
|
|
|
pub fn verify_script(
|
|
|
|
script_sig: &Script,
|
|
|
|
script_pubkey: &Script,
|
|
|
|
flags: &VerificationFlags,
|
|
|
|
checker: &SignatureChecker
|
|
|
|
) -> Result<(), Error> {
|
2016-09-15 02:45:31 -07:00
|
|
|
if flags.verify_sigpushonly && !script_sig.is_push_only() {
|
|
|
|
return Err(Error::SignaturePushOnly);
|
|
|
|
}
|
2016-09-14 10:47:58 -07:00
|
|
|
|
2016-09-17 06:46:53 -07:00
|
|
|
let mut stack = Stack::new();
|
|
|
|
let mut stack_copy = Stack::new();
|
2016-09-14 10:47:58 -07:00
|
|
|
|
|
|
|
try!(eval_script(&mut stack, script_sig, flags, checker, SignatureVersion::Base));
|
|
|
|
|
|
|
|
if flags.verify_p2sh {
|
|
|
|
stack_copy = stack.clone();
|
|
|
|
}
|
|
|
|
|
|
|
|
let res = try!(eval_script(&mut stack, script_pubkey, flags, checker, SignatureVersion::Base));
|
|
|
|
if !res {
|
|
|
|
return Err(Error::EvalFalse);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Additional validation for spend-to-script-hash transactions:
|
|
|
|
if flags.verify_p2sh && script_pubkey.is_pay_to_script_hash() {
|
2016-09-15 02:45:31 -07:00
|
|
|
if !script_sig.is_push_only() {
|
|
|
|
return Err(Error::SignaturePushOnly);
|
|
|
|
}
|
2016-09-14 10:47:58 -07:00
|
|
|
|
|
|
|
mem::swap(&mut stack, &mut stack_copy);
|
|
|
|
|
|
|
|
// stack cannot be empty here, because if it was the
|
|
|
|
// P2SH HASH <> EQUAL scriptPubKey would be evaluated with
|
|
|
|
// an empty stack and the EvalScript above would return false.
|
|
|
|
assert!(!stack.is_empty());
|
|
|
|
|
2016-09-17 06:46:53 -07:00
|
|
|
let pubkey2: Script = try!(stack.pop()).into();
|
2016-09-14 10:47:58 -07:00
|
|
|
|
|
|
|
let res = try!(eval_script(&mut stack, &pubkey2, flags, checker, SignatureVersion::Base));
|
|
|
|
if !res {
|
|
|
|
return Err(Error::EvalFalse);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-15 02:45:31 -07:00
|
|
|
// The CLEANSTACK check is only performed after potential P2SH evaluation,
|
|
|
|
// as the non-P2SH evaluation of a P2SH script will obviously not result in
|
|
|
|
// a clean stack (the P2SH inputs remain). The same holds for witness evaluation.
|
|
|
|
if flags.verify_cleanstack {
|
|
|
|
// Disallow CLEANSTACK without P2SH, as otherwise a switch CLEANSTACK->P2SH+CLEANSTACK
|
|
|
|
// would be possible, which is not a softfork (and P2SH should be one).
|
|
|
|
assert!(flags.verify_p2sh);
|
|
|
|
assert!(flags.verify_witness);
|
|
|
|
if stack.len() != 1 {
|
|
|
|
return Err(Error::Cleanstack);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-14 10:47:58 -07:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2016-08-20 09:25:41 -07:00
|
|
|
pub fn eval_script(
|
2016-09-18 04:30:00 -07:00
|
|
|
stack: &mut Stack<Bytes>,
|
2016-08-23 06:07:14 -07:00
|
|
|
script: &Script,
|
2016-08-23 07:58:06 -07:00
|
|
|
flags: &VerificationFlags,
|
2016-09-08 03:20:18 -07:00
|
|
|
checker: &SignatureChecker,
|
2016-09-11 03:22:25 -07:00
|
|
|
version: SignatureVersion
|
2016-08-22 09:23:32 -07:00
|
|
|
) -> Result<bool, Error> {
|
2016-08-23 06:07:14 -07:00
|
|
|
if script.len() > script::MAX_SCRIPT_SIZE {
|
|
|
|
return Err(Error::ScriptSize);
|
|
|
|
}
|
|
|
|
|
2016-09-11 03:22:25 -07:00
|
|
|
let mut pc = 0;
|
2016-09-15 02:45:31 -07:00
|
|
|
let mut op_count = 0;
|
2016-09-11 03:22:25 -07:00
|
|
|
let mut begincode = 0;
|
|
|
|
let mut exec_stack = Vec::<bool>::new();
|
2016-09-18 04:30:00 -07:00
|
|
|
let mut altstack = Stack::<Bytes>::new();
|
2016-09-08 06:05:57 -07:00
|
|
|
|
2016-09-11 03:22:25 -07:00
|
|
|
while pc < script.len() {
|
2016-09-14 08:48:00 -07:00
|
|
|
let executing = exec_stack.iter().all(|x| *x);
|
2016-09-15 02:45:31 -07:00
|
|
|
let instruction = try!(script.get_instruction(pc));
|
|
|
|
let opcode = instruction.opcode;
|
2016-09-14 08:48:00 -07:00
|
|
|
|
2016-09-15 02:45:31 -07:00
|
|
|
if let Some(data) = instruction.data {
|
|
|
|
if data.len() > script::MAX_SCRIPT_ELEMENT_SIZE {
|
|
|
|
return Err(Error::PushSize);
|
|
|
|
}
|
2016-09-14 08:48:00 -07:00
|
|
|
|
2016-09-15 02:45:31 -07:00
|
|
|
if executing && flags.verify_minimaldata && !check_minimal_push(data, opcode) {
|
|
|
|
return Err(Error::Minimaldata);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if opcode.is_countable() {
|
|
|
|
op_count += 1;
|
|
|
|
if op_count > script::MAX_OPS_PER_SCRIPT {
|
|
|
|
return Err(Error::OpCount);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if opcode.is_disabled() {
|
|
|
|
return Err(Error::DisabledOpcode(opcode));
|
|
|
|
}
|
2016-09-14 08:48:00 -07:00
|
|
|
|
|
|
|
if !(executing || (Opcode::OP_IF <= opcode && opcode <= Opcode::OP_ENDIF)) {
|
2016-09-15 02:45:31 -07:00
|
|
|
pc += instruction.step;
|
2016-09-14 08:48:00 -07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-09-11 03:22:25 -07:00
|
|
|
match opcode {
|
|
|
|
Opcode::OP_PUSHDATA1 |
|
|
|
|
Opcode::OP_PUSHDATA2 |
|
2016-09-15 02:45:31 -07:00
|
|
|
Opcode::OP_PUSHDATA4 |
|
2016-09-11 03:22:25 -07:00
|
|
|
Opcode::OP_0 |
|
|
|
|
Opcode::OP_PUSHBYTES_1 |
|
|
|
|
Opcode::OP_PUSHBYTES_2 |
|
|
|
|
Opcode::OP_PUSHBYTES_3 |
|
|
|
|
Opcode::OP_PUSHBYTES_4 |
|
|
|
|
Opcode::OP_PUSHBYTES_5 |
|
|
|
|
Opcode::OP_PUSHBYTES_6 |
|
|
|
|
Opcode::OP_PUSHBYTES_7 |
|
|
|
|
Opcode::OP_PUSHBYTES_8 |
|
|
|
|
Opcode::OP_PUSHBYTES_9 |
|
|
|
|
Opcode::OP_PUSHBYTES_10 |
|
|
|
|
Opcode::OP_PUSHBYTES_11 |
|
|
|
|
Opcode::OP_PUSHBYTES_12 |
|
|
|
|
Opcode::OP_PUSHBYTES_13 |
|
|
|
|
Opcode::OP_PUSHBYTES_14 |
|
|
|
|
Opcode::OP_PUSHBYTES_15 |
|
|
|
|
Opcode::OP_PUSHBYTES_16 |
|
|
|
|
Opcode::OP_PUSHBYTES_17 |
|
|
|
|
Opcode::OP_PUSHBYTES_18 |
|
|
|
|
Opcode::OP_PUSHBYTES_19 |
|
|
|
|
Opcode::OP_PUSHBYTES_20 |
|
|
|
|
Opcode::OP_PUSHBYTES_21 |
|
|
|
|
Opcode::OP_PUSHBYTES_22 |
|
|
|
|
Opcode::OP_PUSHBYTES_23 |
|
|
|
|
Opcode::OP_PUSHBYTES_24 |
|
|
|
|
Opcode::OP_PUSHBYTES_25 |
|
|
|
|
Opcode::OP_PUSHBYTES_26 |
|
|
|
|
Opcode::OP_PUSHBYTES_27 |
|
|
|
|
Opcode::OP_PUSHBYTES_28 |
|
|
|
|
Opcode::OP_PUSHBYTES_29 |
|
|
|
|
Opcode::OP_PUSHBYTES_30 |
|
|
|
|
Opcode::OP_PUSHBYTES_31 |
|
|
|
|
Opcode::OP_PUSHBYTES_32 |
|
|
|
|
Opcode::OP_PUSHBYTES_33 |
|
|
|
|
Opcode::OP_PUSHBYTES_34 |
|
|
|
|
Opcode::OP_PUSHBYTES_35 |
|
|
|
|
Opcode::OP_PUSHBYTES_36 |
|
|
|
|
Opcode::OP_PUSHBYTES_37 |
|
|
|
|
Opcode::OP_PUSHBYTES_38 |
|
|
|
|
Opcode::OP_PUSHBYTES_39 |
|
|
|
|
Opcode::OP_PUSHBYTES_40 |
|
|
|
|
Opcode::OP_PUSHBYTES_41 |
|
|
|
|
Opcode::OP_PUSHBYTES_42 |
|
|
|
|
Opcode::OP_PUSHBYTES_43 |
|
|
|
|
Opcode::OP_PUSHBYTES_44 |
|
|
|
|
Opcode::OP_PUSHBYTES_45 |
|
|
|
|
Opcode::OP_PUSHBYTES_46 |
|
|
|
|
Opcode::OP_PUSHBYTES_47 |
|
|
|
|
Opcode::OP_PUSHBYTES_48 |
|
|
|
|
Opcode::OP_PUSHBYTES_49 |
|
|
|
|
Opcode::OP_PUSHBYTES_50 |
|
|
|
|
Opcode::OP_PUSHBYTES_51 |
|
|
|
|
Opcode::OP_PUSHBYTES_52 |
|
|
|
|
Opcode::OP_PUSHBYTES_53 |
|
|
|
|
Opcode::OP_PUSHBYTES_54 |
|
|
|
|
Opcode::OP_PUSHBYTES_55 |
|
|
|
|
Opcode::OP_PUSHBYTES_56 |
|
|
|
|
Opcode::OP_PUSHBYTES_57 |
|
|
|
|
Opcode::OP_PUSHBYTES_58 |
|
|
|
|
Opcode::OP_PUSHBYTES_59 |
|
|
|
|
Opcode::OP_PUSHBYTES_60 |
|
|
|
|
Opcode::OP_PUSHBYTES_61 |
|
|
|
|
Opcode::OP_PUSHBYTES_62 |
|
|
|
|
Opcode::OP_PUSHBYTES_63 |
|
|
|
|
Opcode::OP_PUSHBYTES_64 |
|
|
|
|
Opcode::OP_PUSHBYTES_65 |
|
|
|
|
Opcode::OP_PUSHBYTES_66 |
|
|
|
|
Opcode::OP_PUSHBYTES_67 |
|
|
|
|
Opcode::OP_PUSHBYTES_68 |
|
|
|
|
Opcode::OP_PUSHBYTES_69 |
|
|
|
|
Opcode::OP_PUSHBYTES_70 |
|
|
|
|
Opcode::OP_PUSHBYTES_71 |
|
|
|
|
Opcode::OP_PUSHBYTES_72 |
|
|
|
|
Opcode::OP_PUSHBYTES_73 |
|
|
|
|
Opcode::OP_PUSHBYTES_74 |
|
|
|
|
Opcode::OP_PUSHBYTES_75 => {
|
2016-09-15 02:45:31 -07:00
|
|
|
if let Some(data) = instruction.data {
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(data.to_vec().into());
|
2016-08-23 07:58:06 -07:00
|
|
|
}
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
2016-09-14 08:48:00 -07:00
|
|
|
Opcode::OP_1NEGATE |
|
2016-09-11 03:22:25 -07:00
|
|
|
Opcode::OP_1 |
|
|
|
|
Opcode::OP_2 |
|
|
|
|
Opcode::OP_3 |
|
|
|
|
Opcode::OP_4 |
|
|
|
|
Opcode::OP_5 |
|
|
|
|
Opcode::OP_6 |
|
|
|
|
Opcode::OP_7 |
|
|
|
|
Opcode::OP_8 |
|
|
|
|
Opcode::OP_9 |
|
|
|
|
Opcode::OP_10 |
|
|
|
|
Opcode::OP_11 |
|
|
|
|
Opcode::OP_12 |
|
|
|
|
Opcode::OP_13 |
|
|
|
|
Opcode::OP_14 |
|
|
|
|
Opcode::OP_15 |
|
|
|
|
Opcode::OP_16 => {
|
|
|
|
let value = opcode as u8 - (Opcode::OP_1 as u8 - 1);
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(Num::from(value).to_bytes());
|
2016-08-23 06:07:14 -07:00
|
|
|
},
|
2016-09-11 03:22:25 -07:00
|
|
|
Opcode::OP_CAT | Opcode::OP_SUBSTR | Opcode::OP_LEFT | Opcode::OP_RIGHT |
|
|
|
|
Opcode::OP_INVERT | Opcode::OP_AND | Opcode::OP_OR | Opcode::OP_XOR |
|
|
|
|
Opcode::OP_2MUL | Opcode::OP_2DIV | Opcode::OP_MUL | Opcode::OP_DIV |
|
|
|
|
Opcode::OP_MOD | Opcode::OP_LSHIFT | Opcode::OP_RSHIFT => {
|
|
|
|
return Err(Error::DisabledOpcode(opcode));
|
|
|
|
},
|
|
|
|
Opcode::OP_NOP => break,
|
|
|
|
Opcode::OP_CHECKLOCKTIMEVERIFY => {
|
|
|
|
if !flags.verify_clocktimeverify {
|
|
|
|
if flags.verify_discourage_upgradable_nops {
|
|
|
|
return Err(Error::DiscourageUpgradableNops);
|
2016-09-08 03:20:18 -07:00
|
|
|
}
|
2016-09-11 03:22:25 -07:00
|
|
|
}
|
2016-09-08 03:20:18 -07:00
|
|
|
|
2016-09-11 03:22:25 -07:00
|
|
|
// Note that elsewhere numeric opcodes are limited to
|
|
|
|
// operands in the range -2**31+1 to 2**31-1, however it is
|
|
|
|
// legal for opcodes to produce results exceeding that
|
|
|
|
// range. This limitation is implemented by CScriptNum's
|
|
|
|
// default 4-byte limit.
|
|
|
|
//
|
|
|
|
// If we kept to that limit we'd have a year 2038 problem,
|
|
|
|
// even though the nLockTime field in transactions
|
|
|
|
// themselves is uint32 which only becomes meaningless
|
|
|
|
// after the year 2106.
|
|
|
|
//
|
|
|
|
// Thus as a special case we tell CScriptNum to accept up
|
|
|
|
// to 5-byte bignums, which are good until 2**39-1, well
|
|
|
|
// beyond the 2**32-1 limit of the nLockTime field itself.
|
2016-09-17 06:46:53 -07:00
|
|
|
let lock_time = try!(Num::from_slice(try!(stack.last()), flags.verify_minimaldata, 5));
|
2016-09-11 03:22:25 -07:00
|
|
|
|
|
|
|
// In the rare event that the argument may be < 0 due to
|
|
|
|
// some arithmetic being done first, you can always use
|
|
|
|
// 0 MAX CHECKLOCKTIMEVERIFY.
|
|
|
|
if lock_time.is_negative() {
|
|
|
|
return Err(Error::NegativeLocktime);
|
|
|
|
}
|
2016-09-08 03:20:18 -07:00
|
|
|
|
2016-09-11 03:22:25 -07:00
|
|
|
if !checker.check_lock_time(lock_time) {
|
|
|
|
return Err(Error::UnsatisfiedLocktime);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Opcode::OP_CHECKSEQUENCEVERIFY => {
|
|
|
|
if !flags.verify_chechsequenceverify {
|
|
|
|
if flags.verify_discourage_upgradable_nops {
|
|
|
|
return Err(Error::DiscourageUpgradableNops);
|
2016-09-08 06:05:57 -07:00
|
|
|
}
|
2016-09-11 03:22:25 -07:00
|
|
|
}
|
2016-09-08 06:05:57 -07:00
|
|
|
|
2016-09-17 06:46:53 -07:00
|
|
|
let sequence = try!(Num::from_slice(try!(stack.last()), flags.verify_minimaldata, 5));
|
2016-09-08 06:05:57 -07:00
|
|
|
|
2016-09-11 03:22:25 -07:00
|
|
|
if sequence.is_negative() {
|
|
|
|
return Err(Error::NegativeLocktime);
|
|
|
|
}
|
2016-09-08 06:05:57 -07:00
|
|
|
|
2016-09-11 03:22:25 -07:00
|
|
|
if (sequence & (SEQUENCE_LOCKTIME_DISABLE_FLAG as i64).into()).is_zero() {
|
2016-09-08 06:05:57 -07:00
|
|
|
if !checker.check_sequence(sequence) {
|
|
|
|
return Err(Error::UnsatisfiedLocktime);
|
|
|
|
}
|
2016-09-11 03:22:25 -07:00
|
|
|
}
|
|
|
|
},
|
2016-09-14 08:48:00 -07:00
|
|
|
Opcode::OP_NOP1 |
|
|
|
|
Opcode::OP_NOP4 |
|
|
|
|
Opcode::OP_NOP5 |
|
|
|
|
Opcode::OP_NOP6 |
|
|
|
|
Opcode::OP_NOP7 |
|
|
|
|
Opcode::OP_NOP8 |
|
|
|
|
Opcode::OP_NOP9 |
|
|
|
|
Opcode::OP_NOP10 => {
|
2016-09-11 03:22:25 -07:00
|
|
|
if flags.verify_discourage_upgradable_nops {
|
|
|
|
return Err(Error::DiscourageUpgradableNops);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Opcode::OP_IF | Opcode::OP_NOTIF => {
|
|
|
|
let mut exec_value = false;
|
2016-09-14 08:48:00 -07:00
|
|
|
if executing {
|
2016-09-17 06:46:53 -07:00
|
|
|
exec_value = cast_to_bool(&try!(stack.pop().map_err(|_| Error::UnbalancedConditional)));
|
2016-09-11 03:22:25 -07:00
|
|
|
if opcode == Opcode::OP_NOTIF {
|
|
|
|
exec_value = !exec_value;
|
2016-09-08 06:05:57 -07:00
|
|
|
}
|
2016-09-11 03:22:25 -07:00
|
|
|
}
|
|
|
|
exec_stack.push(exec_value);
|
|
|
|
},
|
|
|
|
Opcode::OP_ELSE => {
|
|
|
|
if exec_stack.is_empty() {
|
|
|
|
return Err(Error::UnbalancedConditional);
|
|
|
|
}
|
|
|
|
let last = exec_stack[exec_stack.len() - 1];
|
|
|
|
exec_stack[exec_stack.len() - 1] == !last;
|
|
|
|
},
|
|
|
|
Opcode::OP_ENDIF => {
|
|
|
|
if exec_stack.is_empty() {
|
|
|
|
return Err(Error::UnbalancedConditional);
|
|
|
|
}
|
|
|
|
exec_stack.pop();
|
|
|
|
},
|
|
|
|
Opcode::OP_VERIFY => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let exec_value = cast_to_bool(&try!(stack.pop()));
|
2016-09-11 03:22:25 -07:00
|
|
|
if !exec_value {
|
|
|
|
return Err(Error::Verify);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Opcode::OP_RETURN => {
|
|
|
|
return Err(Error::ReturnOpcode);
|
|
|
|
},
|
|
|
|
Opcode::OP_TOALTSTACK => {
|
2016-09-17 06:46:53 -07:00
|
|
|
altstack.push(try!(stack.pop()));
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_FROMALTSTACK => {
|
2016-09-17 06:46:53 -07:00
|
|
|
stack.push(try!(altstack.pop().map_err(|_| Error::InvalidAltstackOperation)));
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_2DROP => {
|
2016-09-17 06:46:53 -07:00
|
|
|
try!(stack.drop(2));
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_2DUP => {
|
2016-09-17 06:46:53 -07:00
|
|
|
try!(stack.dup(2));
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_3DUP => {
|
2016-09-17 06:46:53 -07:00
|
|
|
try!(stack.dup(3));
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_2OVER => {
|
2016-09-17 06:46:53 -07:00
|
|
|
try!(stack.over(2));
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_2ROT => {
|
2016-09-17 06:46:53 -07:00
|
|
|
try!(stack.rot(2));
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_2SWAP => {
|
2016-09-17 06:46:53 -07:00
|
|
|
try!(stack.swap(2));
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_IFDUP => {
|
2016-09-17 06:46:53 -07:00
|
|
|
if cast_to_bool(try!(stack.last())) {
|
|
|
|
try!(stack.dup(1));
|
2016-09-11 03:22:25 -07:00
|
|
|
}
|
|
|
|
},
|
|
|
|
Opcode::OP_DEPTH => {
|
|
|
|
let depth = Num::from(stack.len());
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(depth.to_bytes());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_DROP => {
|
2016-09-17 06:46:53 -07:00
|
|
|
try!(stack.pop());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_DUP => {
|
2016-09-17 06:46:53 -07:00
|
|
|
try!(stack.dup(1));
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_NIP => {
|
2016-09-17 06:46:53 -07:00
|
|
|
try!(stack.nip());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_OVER => {
|
2016-09-17 06:46:53 -07:00
|
|
|
try!(stack.over(1));
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_PICK | Opcode::OP_ROLL => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let n: i64 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4)).into();
|
2016-09-11 03:22:25 -07:00
|
|
|
if n < 0 || n >= stack.len() as i64 {
|
|
|
|
return Err(Error::InvalidStackOperation);
|
|
|
|
}
|
2016-09-08 06:05:57 -07:00
|
|
|
|
2016-09-17 06:46:53 -07:00
|
|
|
let v = match opcode {
|
|
|
|
Opcode::OP_PICK => try!(stack.top(n as usize)).clone(),
|
|
|
|
_ => try!(stack.remove(n as usize)),
|
|
|
|
};
|
|
|
|
|
2016-09-11 03:22:25 -07:00
|
|
|
stack.push(v);
|
|
|
|
},
|
|
|
|
Opcode::OP_ROT => {
|
2016-09-17 06:46:53 -07:00
|
|
|
try!(stack.rot(1));
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_SWAP => {
|
2016-09-17 06:46:53 -07:00
|
|
|
try!(stack.swap(1));
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_TUCK => {
|
2016-09-17 06:46:53 -07:00
|
|
|
try!(stack.tuck());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_SIZE => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let n = Num::from(try!(stack.last()).len());
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(n.to_bytes());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_EQUAL => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let v1 = try!(stack.pop());
|
|
|
|
let v2 = try!(stack.pop());
|
2016-09-11 03:22:25 -07:00
|
|
|
let to_push = match v1 == v2 {
|
|
|
|
true => vec![1],
|
|
|
|
false => vec![0],
|
|
|
|
};
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(to_push.into());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_EQUALVERIFY => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let equal = try!(stack.pop()) == try!(stack.pop());
|
2016-09-11 03:22:25 -07:00
|
|
|
if !equal {
|
|
|
|
return Err(Error::EqualVerify);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Opcode::OP_1ADD => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let n = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4)) + 1.into();
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(n.to_bytes());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_1SUB => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let n = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4)) - 1.into();
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(n.to_bytes());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_NEGATE => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let n = -try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(n.to_bytes());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_ABS => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let n = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4)).abs();
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(n.to_bytes());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_NOT => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let n = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4)).is_zero();
|
2016-09-11 03:22:25 -07:00
|
|
|
let n = Num::from(n);
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(n.to_bytes());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_0NOTEQUAL => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let n = !try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4)).is_zero();
|
2016-09-11 03:22:25 -07:00
|
|
|
let n = Num::from(n);
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(n.to_bytes());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_ADD => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
|
|
|
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push((v1 + v2).to_bytes());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_SUB => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
|
|
|
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push((v2 - v1).to_bytes());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_BOOLAND => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
|
|
|
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
2016-09-11 03:22:25 -07:00
|
|
|
let v = Num::from(!v1.is_zero() && !v2.is_zero());
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(v.to_bytes());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_BOOLOR => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
|
|
|
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
2016-09-11 03:22:25 -07:00
|
|
|
let v = Num::from(!v1.is_zero() || !v2.is_zero());
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(v.to_bytes());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_NUMEQUAL => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
|
|
|
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
2016-09-11 03:22:25 -07:00
|
|
|
let v = Num::from(v1 == v2);
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(v.to_bytes());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_NUMEQUALVERIFY => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
|
|
|
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
2016-09-11 03:22:25 -07:00
|
|
|
if v1 != v2 {
|
|
|
|
return Err(Error::NumEqualVerify);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Opcode::OP_NUMNOTEQUAL => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
|
|
|
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
2016-09-11 03:22:25 -07:00
|
|
|
let v = Num::from(v1 != v2);
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(v.to_bytes());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_LESSTHAN => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
|
|
|
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
2016-09-11 03:22:25 -07:00
|
|
|
let v = Num::from(v1 > v2);
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(v.to_bytes());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_GREATERTHAN => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
|
|
|
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
2016-09-11 03:22:25 -07:00
|
|
|
let v = Num::from(v1 < v2);
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(v.to_bytes());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_LESSTHANOREQUAL => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
|
|
|
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
2016-09-11 03:22:25 -07:00
|
|
|
let v = Num::from(v1 >= v2);
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(v.to_bytes());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_GREATERTHANOREQUAL => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
|
|
|
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
2016-09-11 03:22:25 -07:00
|
|
|
let v = Num::from(v1 <= v2);
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(v.to_bytes());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_MIN => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
|
|
|
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(cmp::min(v1, v2).to_bytes());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_MAX => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
|
|
|
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(cmp::max(v1, v2).to_bytes());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_WITHIN => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let v1 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
|
|
|
let v2 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
|
|
|
let v3 = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
2016-09-11 03:22:25 -07:00
|
|
|
let to_push = match v2 <= v3 && v3 <= v1 {
|
|
|
|
true => vec![1],
|
|
|
|
false => vec![0],
|
|
|
|
};
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(to_push.into());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_RIPEMD160 => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let v = ripemd160(&try!(stack.pop()));
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(v.to_vec().into());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_SHA1 => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let v = sha1(&try!(stack.pop()));
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(v.to_vec().into());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_SHA256 => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let v = sha256(&try!(stack.pop()));
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(v.to_vec().into());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_HASH160 => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let v = dhash160(&try!(stack.pop()));
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(v.to_vec().into());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_HASH256 => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let v = dhash256(&try!(stack.pop()));
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(v.to_vec().into());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_CODESEPARATOR => {
|
|
|
|
begincode = pc;
|
|
|
|
},
|
|
|
|
Opcode::OP_CHECKSIG | Opcode::OP_CHECKSIGVERIFY => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let pubkey = try!(stack.pop());
|
|
|
|
let signature = try!(stack.pop());
|
2016-09-11 03:22:25 -07:00
|
|
|
let mut subscript = script.subscript(begincode);
|
|
|
|
if version == SignatureVersion::Base {
|
|
|
|
subscript = script.find_and_delete(&signature);
|
|
|
|
}
|
|
|
|
|
|
|
|
try!(check_signature_encoding(&signature, flags));
|
|
|
|
try!(check_pubkey_encoding(&pubkey, flags));
|
|
|
|
|
2016-09-18 04:30:00 -07:00
|
|
|
let success = check_signature(checker, signature.into(), pubkey.into(), &subscript, version);
|
2016-09-11 03:22:25 -07:00
|
|
|
match opcode {
|
|
|
|
Opcode::OP_CHECKSIG => {
|
|
|
|
let to_push = match success {
|
|
|
|
true => vec![1],
|
|
|
|
false => vec![0],
|
|
|
|
};
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(to_push.into());
|
2016-09-11 03:22:25 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_CHECKSIGVERIFY if !success => {
|
|
|
|
return Err(Error::CheckSigVerify);
|
|
|
|
},
|
|
|
|
_ => {},
|
|
|
|
}
|
2016-08-23 06:07:14 -07:00
|
|
|
},
|
2016-09-14 08:48:00 -07:00
|
|
|
Opcode::OP_CHECKMULTISIG | Opcode::OP_CHECKMULTISIGVERIFY => {
|
2016-09-17 06:46:53 -07:00
|
|
|
let keys_count = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
2016-09-14 08:48:00 -07:00
|
|
|
if keys_count < 0.into() || keys_count > script::MAX_PUBKEYS_PER_MULTISIG.into() {
|
|
|
|
return Err(Error::PubkeyCount);
|
|
|
|
}
|
|
|
|
|
2016-09-14 13:58:39 -07:00
|
|
|
let keys_count: usize = keys_count.into();
|
2016-09-17 06:46:53 -07:00
|
|
|
let keys: Vec<_> = try!((0..keys_count).into_iter().map(|_| stack.pop()).rev().collect());
|
2016-09-14 13:58:39 -07:00
|
|
|
|
2016-09-17 06:46:53 -07:00
|
|
|
let sigs_count = try!(Num::from_slice(&try!(stack.pop()), flags.verify_minimaldata, 4));
|
2016-09-14 13:58:39 -07:00
|
|
|
if sigs_count < 0.into() || sigs_count > keys_count.into() {
|
2016-09-14 08:48:00 -07:00
|
|
|
return Err(Error::SigCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
let sigs_count: usize = sigs_count.into();
|
2016-09-17 06:46:53 -07:00
|
|
|
let sigs: Vec<_> = try!((0..sigs_count).into_iter().map(|_| stack.pop()).rev().collect());
|
2016-09-14 08:48:00 -07:00
|
|
|
|
|
|
|
let mut subscript = script.subscript(begincode);
|
|
|
|
|
|
|
|
if version == SignatureVersion::Base {
|
|
|
|
for signature in &sigs {
|
|
|
|
subscript = subscript.find_and_delete(signature);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut success = true;
|
|
|
|
let mut k = 0;
|
|
|
|
let mut s = 0;
|
|
|
|
while s < sigs.len() && success {
|
|
|
|
// TODO: remove redundant copying
|
|
|
|
let key = keys[k].clone();
|
|
|
|
let sig = sigs[s].clone();
|
|
|
|
|
|
|
|
try!(check_signature_encoding(&sig, flags));
|
|
|
|
try!(check_pubkey_encoding(&key, flags));
|
|
|
|
|
2016-09-18 04:30:00 -07:00
|
|
|
let ok = check_signature(checker, sig.into(), key.into(), &subscript, version);
|
2016-09-14 08:48:00 -07:00
|
|
|
if ok {
|
|
|
|
s += 1;
|
|
|
|
}
|
|
|
|
k += 1;
|
|
|
|
|
|
|
|
success = sigs.len() - s <= keys.len() - k;
|
|
|
|
}
|
|
|
|
|
2016-09-17 06:46:53 -07:00
|
|
|
if !try!(stack.pop()).is_empty() && flags.verify_nulldummy {
|
2016-09-14 08:48:00 -07:00
|
|
|
return Err(Error::SignatureNullDummy);
|
|
|
|
}
|
|
|
|
|
|
|
|
match opcode {
|
|
|
|
Opcode::OP_CHECKMULTISIG => {
|
|
|
|
let to_push = match success {
|
|
|
|
true => vec![1],
|
|
|
|
false => vec![0],
|
|
|
|
};
|
2016-09-18 04:30:00 -07:00
|
|
|
stack.push(to_push.into());
|
2016-09-14 08:48:00 -07:00
|
|
|
},
|
|
|
|
Opcode::OP_CHECKMULTISIGVERIFY if !success => {
|
|
|
|
return Err(Error::CheckSigVerify);
|
|
|
|
},
|
|
|
|
_ => {},
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Opcode::OP_RESERVED |
|
|
|
|
Opcode::OP_VER |
|
|
|
|
Opcode::OP_RESERVED1 |
|
2016-09-15 02:45:31 -07:00
|
|
|
Opcode::OP_RESERVED2 => {
|
|
|
|
if executing {
|
|
|
|
return Err(Error::DisabledOpcode(opcode));
|
|
|
|
}
|
|
|
|
},
|
2016-09-14 08:48:00 -07:00
|
|
|
Opcode::OP_VERIF |
|
2016-09-15 02:45:31 -07:00
|
|
|
Opcode::OP_VERNOTIF => {
|
|
|
|
return Err(Error::DisabledOpcode(opcode));
|
|
|
|
},
|
2016-08-23 06:07:14 -07:00
|
|
|
}
|
2016-09-14 08:48:00 -07:00
|
|
|
|
|
|
|
if stack.len() + altstack.len() > 1000 {
|
|
|
|
return Err(Error::StackSize);
|
|
|
|
}
|
|
|
|
|
2016-09-15 02:45:31 -07:00
|
|
|
pc += instruction.step;
|
2016-08-23 06:07:14 -07:00
|
|
|
}
|
|
|
|
|
2016-09-14 08:48:00 -07:00
|
|
|
if !exec_stack.is_empty() {
|
|
|
|
return Err(Error::UnbalancedConditional);
|
|
|
|
}
|
|
|
|
|
2016-09-08 03:20:18 -07:00
|
|
|
let success = !stack.is_empty() && {
|
2016-09-17 06:46:53 -07:00
|
|
|
let last = try!(stack.last());
|
2016-09-14 03:14:17 -07:00
|
|
|
cast_to_bool(last)
|
2016-09-08 03:20:18 -07:00
|
|
|
};
|
|
|
|
|
2016-09-08 07:40:07 -07:00
|
|
|
Ok(success)
|
2016-08-19 06:40:32 -07:00
|
|
|
}
|
2016-08-22 09:23:32 -07:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use hex::FromHex;
|
2016-09-18 09:12:45 -07:00
|
|
|
use primitives::Bytes;
|
|
|
|
use chain::Transaction;
|
2016-09-14 03:54:32 -07:00
|
|
|
use script::{
|
|
|
|
Opcode, Script, VerificationFlags, Builder, Error, Num, TransactionInputSigner,
|
2016-09-17 06:46:53 -07:00
|
|
|
NoopSignatureChecker, SignatureVersion, TransactionSignatureChecker, Stack
|
2016-09-14 03:54:32 -07:00
|
|
|
};
|
2016-09-14 10:47:58 -07:00
|
|
|
use super::{eval_script, verify_script, is_public_key};
|
2016-08-22 09:23:32 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn tests_is_public_key() {
|
|
|
|
assert!(!is_public_key(&[]));
|
|
|
|
assert!(!is_public_key(&[1]));
|
|
|
|
assert!(is_public_key(&"0495dfb90f202c7d016ef42c65bc010cd26bb8237b06253cc4d12175097bef767ed6b1fcb3caf1ed57c98d92e6cb70278721b952e29a335134857acd4c199b9d2f".from_hex().unwrap()));
|
|
|
|
assert!(is_public_key(&[2; 33]));
|
|
|
|
assert!(is_public_key(&[3; 33]));
|
|
|
|
assert!(!is_public_key(&[4; 33]));
|
|
|
|
}
|
2016-09-07 07:15:07 -07:00
|
|
|
|
|
|
|
// https://github.com/bitcoin/bitcoin/blob/d612837814020ae832499d18e6ee5eb919a87907/src/test/script_tests.cpp#L900
|
|
|
|
#[test]
|
|
|
|
fn test_push_data() {
|
2016-09-18 04:30:00 -07:00
|
|
|
let expected: Stack<Bytes> = vec![vec![0x5a].into()].into();
|
2016-09-08 07:40:07 -07:00
|
|
|
let flags = VerificationFlags::default()
|
|
|
|
.verify_p2sh(true);
|
2016-09-07 07:15:07 -07:00
|
|
|
let checker = NoopSignatureChecker;
|
|
|
|
let version = SignatureVersion::Base;
|
2016-09-18 04:30:00 -07:00
|
|
|
let direct: Script = vec![Opcode::OP_PUSHBYTES_1 as u8, 0x5a].into();
|
|
|
|
let pushdata1: Script = vec![Opcode::OP_PUSHDATA1 as u8, 0x1, 0x5a].into();
|
|
|
|
let pushdata2: Script = vec![Opcode::OP_PUSHDATA2 as u8, 0x1, 0, 0x5a].into();
|
|
|
|
let pushdata4: Script = vec![Opcode::OP_PUSHDATA4 as u8, 0x1, 0, 0, 0, 0x5a].into();
|
2016-09-07 07:15:07 -07:00
|
|
|
|
2016-09-17 06:46:53 -07:00
|
|
|
let mut direct_stack = Stack::new();
|
|
|
|
let mut pushdata1_stack = Stack::new();
|
|
|
|
let mut pushdata2_stack = Stack::new();
|
|
|
|
let mut pushdata4_stack = Stack::new();
|
2016-09-07 07:15:07 -07:00
|
|
|
assert!(eval_script(&mut direct_stack, &direct, &flags, &checker, version).unwrap());
|
|
|
|
assert!(eval_script(&mut pushdata1_stack, &pushdata1, &flags, &checker, version).unwrap());
|
|
|
|
assert!(eval_script(&mut pushdata2_stack, &pushdata2, &flags, &checker, version).unwrap());
|
|
|
|
assert!(eval_script(&mut pushdata4_stack, &pushdata4, &flags, &checker, version).unwrap());
|
|
|
|
|
2016-09-17 06:46:53 -07:00
|
|
|
assert_eq!(direct_stack, expected);
|
|
|
|
assert_eq!(pushdata1_stack, expected);
|
|
|
|
assert_eq!(pushdata2_stack, expected);
|
|
|
|
assert_eq!(pushdata4_stack, expected);
|
2016-09-07 07:15:07 -07:00
|
|
|
}
|
2016-09-08 07:40:07 -07:00
|
|
|
|
2016-09-18 04:30:00 -07:00
|
|
|
fn basic_test(script: &Script, expected: Result<bool, Error>, expected_stack: Stack<Bytes>) {
|
2016-09-08 07:40:07 -07:00
|
|
|
let flags = VerificationFlags::default()
|
|
|
|
.verify_p2sh(true);
|
|
|
|
let checker = NoopSignatureChecker;
|
|
|
|
let version = SignatureVersion::Base;
|
2016-09-17 06:46:53 -07:00
|
|
|
let mut stack = Stack::new();
|
2016-09-08 07:40:07 -07:00
|
|
|
assert_eq!(eval_script(&mut stack, script, &flags, &checker, version), expected);
|
|
|
|
if expected.is_ok() {
|
2016-09-18 04:30:00 -07:00
|
|
|
assert_eq!(stack, expected_stack);
|
2016-09-08 07:40:07 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_equal() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_data(&[0x4])
|
|
|
|
.push_data(&[0x4])
|
|
|
|
.push_opcode(Opcode::OP_EQUAL)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![vec![1].into()].into();
|
2016-09-08 07:40:07 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_equal_false() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_data(&[0x4])
|
|
|
|
.push_data(&[0x3])
|
|
|
|
.push_opcode(Opcode::OP_EQUAL)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(false);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![vec![0].into()].into();
|
2016-09-08 07:40:07 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_equal_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_data(&[0x4])
|
|
|
|
.push_opcode(Opcode::OP_EQUAL)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-08 07:40:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_equal_verify() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_data(&[0x4])
|
|
|
|
.push_data(&[0x4])
|
|
|
|
.push_opcode(Opcode::OP_EQUALVERIFY)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(false);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = Stack::default();
|
2016-09-08 07:40:07 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_equal_verify_failed() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_data(&[0x4])
|
|
|
|
.push_data(&[0x3])
|
|
|
|
.push_opcode(Opcode::OP_EQUALVERIFY)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::EqualVerify);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-08 07:40:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_equal_verify_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_data(&[0x4])
|
|
|
|
.push_opcode(Opcode::OP_EQUALVERIFY)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-08 07:40:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_size() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_data(&[0x12, 0x34])
|
|
|
|
.push_opcode(Opcode::OP_SIZE)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![vec![0x12, 0x34].into(), vec![0x2].into()].into();
|
2016-09-08 07:40:07 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_size_false() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_data(&[])
|
|
|
|
.push_opcode(Opcode::OP_SIZE)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(false);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![vec![].into(), vec![].into()].into();
|
2016-09-08 07:40:07 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_size_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_opcode(Opcode::OP_SIZE)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-08 07:40:07 -07:00
|
|
|
}
|
2016-09-09 01:49:08 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_hash256() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_data(b"hello")
|
|
|
|
.push_opcode(Opcode::OP_HASH256)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec!["9595c9df90075148eb06860365df33584b75bff782a510c6cd4883a419833d50".into()].into();
|
2016-09-09 01:49:08 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_hash256_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_opcode(Opcode::OP_HASH256)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-09 01:49:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_ripemd160() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_data(b"hello")
|
|
|
|
.push_opcode(Opcode::OP_RIPEMD160)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec!["108f07b8382412612c048d07d13f814118445acd".into()].into();
|
2016-09-09 01:49:08 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_ripemd160_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_opcode(Opcode::OP_RIPEMD160)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-09 01:49:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_sha1() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_data(b"hello")
|
|
|
|
.push_opcode(Opcode::OP_SHA1)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec!["aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d".into()].into();
|
2016-09-09 01:49:08 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_sha1_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_opcode(Opcode::OP_SHA1)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-09 01:49:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_sha256() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_data(b"hello")
|
|
|
|
.push_opcode(Opcode::OP_SHA256)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec!["2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824".into()].into();
|
2016-09-09 01:49:08 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_sha256_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_opcode(Opcode::OP_SHA256)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-09 01:49:08 -07:00
|
|
|
}
|
2016-09-09 03:24:57 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_1add() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(5.into())
|
|
|
|
.push_opcode(Opcode::OP_1ADD)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(6).to_bytes()].into();
|
2016-09-09 03:24:57 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_1add_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_opcode(Opcode::OP_1ADD)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-09 03:24:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_1sub() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(5.into())
|
|
|
|
.push_opcode(Opcode::OP_1SUB)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(4).to_bytes()].into();
|
2016-09-09 03:24:57 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_1sub_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_opcode(Opcode::OP_1SUB)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-09 03:24:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_negate() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(5.into())
|
|
|
|
.push_opcode(Opcode::OP_NEGATE)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(-5).to_bytes()].into();
|
2016-09-09 03:24:57 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_negate_negative() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num((-5).into())
|
|
|
|
.push_opcode(Opcode::OP_NEGATE)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(5).to_bytes()].into();
|
2016-09-09 03:24:57 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_negate_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_opcode(Opcode::OP_NEGATE)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-09 03:24:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_abs() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(5.into())
|
|
|
|
.push_opcode(Opcode::OP_ABS)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(5).to_bytes()].into();
|
2016-09-09 03:24:57 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_abs_negative() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num((-5).into())
|
|
|
|
.push_opcode(Opcode::OP_ABS)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(5).to_bytes()].into();
|
2016-09-09 03:24:57 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_abs_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_opcode(Opcode::OP_ABS)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-09 03:24:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_not() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(4.into())
|
|
|
|
.push_opcode(Opcode::OP_NOT)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(false);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(0).to_bytes()].into();
|
2016-09-09 03:24:57 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_not_zero() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(0.into())
|
|
|
|
.push_opcode(Opcode::OP_NOT)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(1).to_bytes()].into();
|
2016-09-09 03:24:57 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_not_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_opcode(Opcode::OP_NOT)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-09 03:24:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_0notequal() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(4.into())
|
|
|
|
.push_opcode(Opcode::OP_0NOTEQUAL)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(1).to_bytes()].into();
|
2016-09-09 03:24:57 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_0notequal_zero() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(0.into())
|
|
|
|
.push_opcode(Opcode::OP_0NOTEQUAL)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(false);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(0).to_bytes()].into();
|
2016-09-09 03:24:57 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_0notequal_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_opcode(Opcode::OP_0NOTEQUAL)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-09 03:24:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_add() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_num(3.into())
|
|
|
|
.push_opcode(Opcode::OP_ADD)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(5).to_bytes()].into();
|
2016-09-09 03:24:57 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_add_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_opcode(Opcode::OP_ADD)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-09 03:24:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_sub() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(3.into())
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_opcode(Opcode::OP_SUB)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(1).to_bytes()].into();
|
2016-09-09 03:24:57 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_sub_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_opcode(Opcode::OP_SUB)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-09 03:24:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_booland() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(3.into())
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_opcode(Opcode::OP_BOOLAND)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(1).to_bytes()].into();
|
2016-09-09 03:24:57 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_booland_first() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_num(0.into())
|
|
|
|
.push_opcode(Opcode::OP_BOOLAND)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(false);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(0).to_bytes()].into();
|
2016-09-09 03:24:57 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_booland_second() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(0.into())
|
|
|
|
.push_num(3.into())
|
|
|
|
.push_opcode(Opcode::OP_BOOLAND)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(false);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(0).to_bytes()].into();
|
2016-09-09 03:24:57 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_booland_none() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(0.into())
|
|
|
|
.push_num(0.into())
|
|
|
|
.push_opcode(Opcode::OP_BOOLAND)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(false);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(0).to_bytes()].into();
|
2016-09-09 03:24:57 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_booland_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(0.into())
|
|
|
|
.push_opcode(Opcode::OP_BOOLAND)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-09 03:24:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_boolor() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(3.into())
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_opcode(Opcode::OP_BOOLOR)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(1).to_bytes()].into();
|
2016-09-09 03:24:57 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_boolor_first() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_num(0.into())
|
|
|
|
.push_opcode(Opcode::OP_BOOLOR)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(1).to_bytes()].into();
|
2016-09-09 03:24:57 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_boolor_second() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(0.into())
|
|
|
|
.push_num(3.into())
|
|
|
|
.push_opcode(Opcode::OP_BOOLOR)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(1).to_bytes()].into();
|
2016-09-09 03:24:57 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_boolor_none() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(0.into())
|
|
|
|
.push_num(0.into())
|
|
|
|
.push_opcode(Opcode::OP_BOOLOR)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(false);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(0).to_bytes()].into();
|
2016-09-09 03:24:57 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_boolor_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(0.into())
|
|
|
|
.push_opcode(Opcode::OP_BOOLOR)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-09 03:24:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_numequal() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_opcode(Opcode::OP_NUMEQUAL)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(1).to_bytes()].into();
|
2016-09-09 03:24:57 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_numequal_not() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_num(3.into())
|
|
|
|
.push_opcode(Opcode::OP_NUMEQUAL)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(false);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(0).to_bytes()].into();
|
2016-09-09 03:24:57 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_numequal_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_opcode(Opcode::OP_NUMEQUAL)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-09 03:24:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_numequalverify() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_opcode(Opcode::OP_NUMEQUALVERIFY)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(false);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-09 03:24:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_numequalverify_failed() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_num(3.into())
|
|
|
|
.push_opcode(Opcode::OP_NUMEQUALVERIFY)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::NumEqualVerify);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-09 03:24:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_numequalverify_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_opcode(Opcode::OP_NUMEQUALVERIFY)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-09 03:24:57 -07:00
|
|
|
}
|
|
|
|
|
2016-09-09 05:23:32 -07:00
|
|
|
#[test]
|
|
|
|
fn test_numnotequal() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_num(3.into())
|
|
|
|
.push_opcode(Opcode::OP_NUMNOTEQUAL)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(1).to_bytes()].into();
|
2016-09-09 05:23:32 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_numnotequal_not() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_opcode(Opcode::OP_NUMNOTEQUAL)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(false);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(0).to_bytes()].into();
|
2016-09-09 05:23:32 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_numnotequal_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_opcode(Opcode::OP_NUMNOTEQUAL)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-09 05:23:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_lessthan() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_num(3.into())
|
|
|
|
.push_opcode(Opcode::OP_LESSTHAN)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(1).to_bytes()].into();
|
2016-09-09 05:23:32 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_lessthan_not() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_opcode(Opcode::OP_LESSTHAN)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(false);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(0).to_bytes()].into();
|
2016-09-09 05:23:32 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_lessthan_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_opcode(Opcode::OP_LESSTHAN)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-09 05:23:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_greaterthan() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(3.into())
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_opcode(Opcode::OP_GREATERTHAN)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(1).to_bytes()].into();
|
2016-09-09 05:23:32 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_greaterthan_not() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_opcode(Opcode::OP_GREATERTHAN)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(false);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(0).to_bytes()].into();
|
2016-09-09 05:23:32 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_greaterthan_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_opcode(Opcode::OP_GREATERTHAN)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-09 05:23:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_lessthanorequal() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_num(3.into())
|
|
|
|
.push_opcode(Opcode::OP_LESSTHANOREQUAL)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(1).to_bytes()].into();
|
2016-09-09 05:23:32 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_lessthanorequal_equal() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_opcode(Opcode::OP_LESSTHANOREQUAL)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(1).to_bytes()].into();
|
2016-09-09 05:23:32 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_lessthanorequal_not() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_num(1.into())
|
|
|
|
.push_opcode(Opcode::OP_LESSTHANOREQUAL)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(false);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(0).to_bytes()].into();
|
2016-09-09 05:23:32 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_lessthanorequal_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_opcode(Opcode::OP_LESSTHANOREQUAL)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-09 05:23:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_greaterthanorequal() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(3.into())
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_opcode(Opcode::OP_GREATERTHANOREQUAL)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(1).to_bytes()].into();
|
2016-09-09 05:23:32 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_greaterthanorequal_equal() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_opcode(Opcode::OP_GREATERTHANOREQUAL)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(1).to_bytes()].into();
|
2016-09-09 05:23:32 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_greaterthanorequal_not() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(1.into())
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_opcode(Opcode::OP_GREATERTHANOREQUAL)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(false);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(0).to_bytes()].into();
|
2016-09-09 05:23:32 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_greaterthanorequal_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_opcode(Opcode::OP_GREATERTHANOREQUAL)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-09 05:23:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_min() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_num(3.into())
|
|
|
|
.push_opcode(Opcode::OP_MIN)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(2).to_bytes()].into();
|
2016-09-09 05:23:32 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_min_second() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(4.into())
|
|
|
|
.push_num(3.into())
|
|
|
|
.push_opcode(Opcode::OP_MIN)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(3).to_bytes()].into();
|
2016-09-09 05:23:32 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_min_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(4.into())
|
|
|
|
.push_opcode(Opcode::OP_MIN)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-09 05:23:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_max() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_num(3.into())
|
|
|
|
.push_opcode(Opcode::OP_MAX)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(3).to_bytes()].into();
|
2016-09-09 05:23:32 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_max_second() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(4.into())
|
|
|
|
.push_num(3.into())
|
|
|
|
.push_opcode(Opcode::OP_MAX)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![Num::from(4).to_bytes()].into();
|
2016-09-09 05:23:32 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_max_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(4.into())
|
|
|
|
.push_opcode(Opcode::OP_MAX)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-09 05:23:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_within() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(3.into())
|
|
|
|
.push_num(2.into())
|
|
|
|
.push_num(4.into())
|
|
|
|
.push_opcode(Opcode::OP_WITHIN)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(true);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![vec![1].into()].into();
|
2016-09-09 05:23:32 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_within_not() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(3.into())
|
|
|
|
.push_num(5.into())
|
|
|
|
.push_num(4.into())
|
|
|
|
.push_opcode(Opcode::OP_WITHIN)
|
|
|
|
.into_script();
|
|
|
|
let result = Ok(false);
|
2016-09-18 04:30:00 -07:00
|
|
|
let stack = vec![vec![0].into()].into();
|
2016-09-09 05:23:32 -07:00
|
|
|
basic_test(&script, result, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_within_invalid_stack() {
|
|
|
|
let script = Builder::default()
|
|
|
|
.push_num(5.into())
|
|
|
|
.push_num(4.into())
|
|
|
|
.push_opcode(Opcode::OP_WITHIN)
|
|
|
|
.into_script();
|
|
|
|
let result = Err(Error::InvalidStackOperation);
|
2016-09-18 04:30:00 -07:00
|
|
|
basic_test(&script, result, Stack::default());
|
2016-09-09 05:23:32 -07:00
|
|
|
}
|
2016-09-14 03:14:17 -07:00
|
|
|
|
|
|
|
// https://blockchain.info/rawtx/3f285f083de7c0acabd9f106a43ec42687ab0bebe2e6f0d529db696794540fea
|
|
|
|
#[test]
|
|
|
|
fn test_check_transaction_signature() {
|
|
|
|
let tx: Transaction = "0100000001484d40d45b9ea0d652fca8258ab7caa42541eb52975857f96fb50cd732c8b481000000008a47304402202cb265bf10707bf49346c3515dd3d16fc454618c58ec0a0ff448a676c54ff71302206c6624d762a1fcef4618284ead8f08678ac05b13c84235f1654e6ad168233e8201410414e301b2328f17442c0b8310d787bf3d8a404cfbd0704f135b6ad4b2d3ee751310f981926e53a6e8c39bd7d3fefd576c543cce493cbac06388f2651d1aacbfcdffffffff0162640100000000001976a914c8e90996c7c6080ee06284600c684ed904d14c5c88ac00000000".into();
|
|
|
|
let signer: TransactionInputSigner = tx.into();
|
|
|
|
let checker = TransactionSignatureChecker {
|
|
|
|
signer: signer,
|
|
|
|
input_index: 0,
|
|
|
|
};
|
|
|
|
let input: Script = "47304402202cb265bf10707bf49346c3515dd3d16fc454618c58ec0a0ff448a676c54ff71302206c6624d762a1fcef4618284ead8f08678ac05b13c84235f1654e6ad168233e8201410414e301b2328f17442c0b8310d787bf3d8a404cfbd0704f135b6ad4b2d3ee751310f981926e53a6e8c39bd7d3fefd576c543cce493cbac06388f2651d1aacbfcd".into();
|
|
|
|
let output: Script = "76a914df3bd30160e6c6145baaf2c88a8844c13a00d1d588ac".into();
|
|
|
|
let flags = VerificationFlags::default()
|
|
|
|
.verify_p2sh(true);
|
2016-09-14 10:47:58 -07:00
|
|
|
assert_eq!(verify_script(&input, &output, &flags, &checker), Ok(()));
|
|
|
|
}
|
|
|
|
|
|
|
|
// https://blockchain.info/rawtx/02b082113e35d5386285094c2829e7e2963fa0b5369fb7f4b79c4c90877dcd3d
|
|
|
|
#[test]
|
|
|
|
fn test_check_transaction_multisig() {
|
|
|
|
let tx: Transaction = "01000000013dcd7d87904c9cb7f4b79f36b5a03f96e2e729284c09856238d5353e1182b00200000000fd5e0100483045022100deeb1f13b5927b5e32d877f3c42a4b028e2e0ce5010fdb4e7f7b5e2921c1dcd2022068631cb285e8c1be9f061d2968a18c3163b780656f30a049effee640e80d9bff01483045022100ee80e164622c64507d243bd949217d666d8b16486e153ac6a1f8e04c351b71a502203691bef46236ca2b4f5e60a82a853a33d6712d6a1e7bf9a65e575aeb7328db8c014cc9524104a882d414e478039cd5b52a92ffb13dd5e6bd4515497439dffd691a0f12af9575fa349b5694ed3155b136f09e63975a1700c9f4d4df849323dac06cf3bd6458cd41046ce31db9bdd543e72fe3039a1f1c047dab87037c36a669ff90e28da1848f640de68c2fe913d363a51154a0c62d7adea1b822d05035077418267b1a1379790187410411ffd36c70776538d079fbae117dc38effafb33304af83ce4894589747aee1ef992f63280567f52f5ba870678b4ab4ff6c8ea600bd217870a8b4f1f09f3a8e8353aeffffffff0130d90000000000001976a914569076ba39fc4ff6a2291d9ea9196d8c08f9c7ab88ac00000000".into();
|
|
|
|
let signer: TransactionInputSigner = tx.into();
|
|
|
|
let checker = TransactionSignatureChecker {
|
|
|
|
signer: signer,
|
|
|
|
input_index: 0,
|
|
|
|
};
|
2016-09-15 06:30:15 -07:00
|
|
|
let input: Script = "00483045022100deeb1f13b5927b5e32d877f3c42a4b028e2e0ce5010fdb4e7f7b5e2921c1dcd2022068631cb285e8c1be9f061d2968a18c3163b780656f30a049effee640e80d9bff01483045022100ee80e164622c64507d243bd949217d666d8b16486e153ac6a1f8e04c351b71a502203691bef46236ca2b4f5e60a82a853a33d6712d6a1e7bf9a65e575aeb7328db8c014cc9524104a882d414e478039cd5b52a92ffb13dd5e6bd4515497439dffd691a0f12af9575fa349b5694ed3155b136f09e63975a1700c9f4d4df849323dac06cf3bd6458cd41046ce31db9bdd543e72fe3039a1f1c047dab87037c36a669ff90e28da1848f640de68c2fe913d363a51154a0c62d7adea1b822d05035077418267b1a1379790187410411ffd36c70776538d079fbae117dc38effafb33304af83ce4894589747aee1ef992f63280567f52f5ba870678b4ab4ff6c8ea600bd217870a8b4f1f09f3a8e8353ae".into();
|
2016-09-14 10:47:58 -07:00
|
|
|
let output: Script = "a9141a8b0026343166625c7475f01e48b5ede8c0252e87".into();
|
|
|
|
let flags = VerificationFlags::default()
|
|
|
|
.verify_p2sh(true);
|
|
|
|
assert_eq!(verify_script(&input, &output, &flags, &checker), Ok(()));
|
2016-09-14 03:14:17 -07:00
|
|
|
}
|
2016-08-22 09:23:32 -07:00
|
|
|
}
|