diff --git a/README.md b/README.md index ae07554f..1e4bc664 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,12 @@ GitHub Workflow Status Bitcoin + Cairo + React Exploration Team +Telegram +X diff --git a/Scarb.lock b/Scarb.lock index 69689ee9..c302a5a8 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -17,6 +17,7 @@ version = "0.1.0" dependencies = [ "shinigami_compiler", "shinigami_engine", + "shinigami_tests", "shinigami_utils", ] @@ -34,7 +35,15 @@ version = "0.1.0" dependencies = [ "ripemd160", "sha1", + "shinigami_utils", +] + +[[package]] +name = "shinigami_tests" +version = "0.1.0" +dependencies = [ "shinigami_compiler", + "shinigami_engine", "shinigami_utils", ] diff --git a/packages/cmds/Scarb.toml b/packages/cmds/Scarb.toml index 80089d4b..67b3b62a 100644 --- a/packages/cmds/Scarb.toml +++ b/packages/cmds/Scarb.toml @@ -6,6 +6,7 @@ edition = "2024_07" [dependencies] shinigami_compiler = { path = "../compiler" } shinigami_engine = { path = "../engine" } +shinigami_tests = { path = "../tests" } shinigami_utils = { path = "../utils" } [dev-dependencies] diff --git a/packages/cmds/src/main.cairo b/packages/cmds/src/main.cairo index c210c958..ba1f1c38 100644 --- a/packages/cmds/src/main.cairo +++ b/packages/cmds/src/main.cairo @@ -1,12 +1,13 @@ use shinigami_compiler::compiler::CompilerImpl; -use shinigami_engine::engine::EngineInternalImpl; -use shinigami_engine::transaction::{TransactionImpl, TransactionTrait}; -use shinigami_engine::utxo::UTXO; -use shinigami_engine::validate; -use shinigami_engine::scriptflags; +use shinigami_engine::engine::{EngineImpl, EngineInternalImpl}; +use shinigami_engine::transaction::{EngineInternalTransactionImpl, EngineInternalTransactionTrait}; +use shinigami_engine::flags; use shinigami_engine::witness; +use shinigami_engine::hash_cache::HashCacheImpl; use shinigami_utils::byte_array::felt252_to_byte_array; use shinigami_utils::bytecode::hex_to_bytecode; +use shinigami_tests::utxo::UTXO; +use shinigami_tests::validate; #[derive(Clone, Drop)] struct InputData { @@ -40,9 +41,10 @@ fn run_with_flags(input: InputDataWithFlags) -> Result<(), felt252> { let script_pubkey = compiler.compile(input.ScriptPubKey)?; let compiler = CompilerImpl::new(); let script_sig = compiler.compile(input.ScriptSig)?; - let tx = TransactionImpl::new_signed(script_sig); - let flags = scriptflags::parse_flags(input.Flags); - let mut engine = EngineInternalImpl::new(@script_pubkey, tx, 0, flags, 0)?; + let tx = EngineInternalTransactionImpl::new_signed(script_sig, script_pubkey.clone()); + let flags = flags::parse_flags(input.Flags); + let hash_cache = HashCacheImpl::new(@tx); + let mut engine = EngineImpl::new(@script_pubkey, @tx, 0, flags, 0, @hash_cache)?; let _ = engine.execute()?; Result::Ok(()) } @@ -60,9 +62,13 @@ fn run_with_witness(input: InputDataWithWitness) -> Result<(), felt252> { let compiler = CompilerImpl::new(); let script_sig = compiler.compile(input.ScriptSig)?; let witness = witness::parse_witness_input(input.Witness); - let tx = TransactionImpl::new_signed_witness(script_sig, witness); - let flags = scriptflags::parse_flags(input.Flags); - let mut engine = EngineInternalImpl::new(@script_pubkey, tx, 0, flags, 0)?; + let value = 1; // TODO + let tx = EngineInternalTransactionImpl::new_signed_witness( + script_sig, script_pubkey.clone(), witness, value + ); + let flags = flags::parse_flags(input.Flags); + let hash_cache = HashCacheImpl::new(@tx); + let mut engine = EngineImpl::new(@script_pubkey, @tx, 0, flags, value, @hash_cache)?; let _ = engine.execute()?; Result::Ok(()) } @@ -77,8 +83,9 @@ fn run(input: InputData) -> Result<(), felt252> { let script_pubkey = compiler.compile(input.ScriptPubKey)?; let compiler = CompilerImpl::new(); let script_sig = compiler.compile(input.ScriptSig)?; - let tx = TransactionImpl::new_signed(script_sig); - let mut engine = EngineInternalImpl::new(@script_pubkey, tx, 0, 0, 0)?; + let tx = EngineInternalTransactionImpl::new_signed(script_sig, script_pubkey.clone()); + let hash_cache = HashCacheImpl::new(@tx); + let mut engine = EngineImpl::new(@script_pubkey, @tx, 0, 0, 0, @hash_cache)?; let _ = engine.execute()?; Result::Ok(()) } @@ -93,8 +100,9 @@ fn run_with_json(input: InputData) -> Result<(), felt252> { let script_pubkey = compiler.compile(input.ScriptPubKey)?; let compiler = CompilerImpl::new(); let script_sig = compiler.compile(input.ScriptSig)?; - let tx = TransactionImpl::new_signed(script_sig); - let mut engine = EngineInternalImpl::new(@script_pubkey, tx, 0, 0, 0)?; + let tx = EngineInternalTransactionImpl::new_signed(script_sig, script_pubkey.clone()); + let hash_cache = HashCacheImpl::new(@tx); + let mut engine = EngineImpl::new(@script_pubkey, @tx, 0, 0, 0, @hash_cache)?; let _ = engine.execute()?; engine.json(); Result::Ok(()) @@ -110,8 +118,9 @@ fn debug(input: InputData) -> Result { let script_pubkey = compiler.compile(input.ScriptPubKey)?; let compiler = CompilerImpl::new(); let script_sig = compiler.compile(input.ScriptSig)?; - let tx = TransactionImpl::new_signed(script_sig); - let mut engine = EngineInternalImpl::new(@script_pubkey, tx, 0, 0, 0)?; + let tx = EngineInternalTransactionImpl::new_signed(script_sig, script_pubkey.clone()); + let hash_cache = HashCacheImpl::new(@tx); + let mut engine = EngineImpl::new(@script_pubkey, @tx, 0, 0, 0, @hash_cache)?; let mut res = Result::Ok(true); while true { res = engine.step(); @@ -188,11 +197,26 @@ struct ValidateRawInput { utxo_hints: Array } -fn run_raw_transaction(input: ValidateRawInput) -> u8 { +fn run_raw_transaction(mut input: ValidateRawInput) -> u8 { println!("Running Bitcoin Script with raw transaction: '{}'", input.raw_transaction); let raw_transaction = hex_to_bytecode(@input.raw_transaction); - let transaction = TransactionTrait::deserialize(raw_transaction); - let res = validate::validate_transaction(transaction, 0, input.utxo_hints); + let transaction = EngineInternalTransactionTrait::deserialize(raw_transaction); + let mut utxo_hints = array![]; + for hint in input + .utxo_hints + .span() { + println!("UTXO hint: 'amount: {}, script_pubkey: {}'", hint.amount, hint.pubkey_script); + let pubkey_script = hex_to_bytecode(hint.pubkey_script); + utxo_hints + .append( + UTXO { + amount: *hint.amount, + pubkey_script: pubkey_script, + block_height: *hint.block_height, + } + ); + }; + let res = validate::validate_transaction(@transaction, 0, utxo_hints); match res { Result::Ok(_) => { println!("Execution successful"); diff --git a/packages/compiler/src/compiler.cairo b/packages/compiler/src/compiler.cairo index 0e46d067..c089c320 100644 --- a/packages/compiler/src/compiler.cairo +++ b/packages/compiler/src/compiler.cairo @@ -26,7 +26,7 @@ pub impl CompilerImpl of CompilerTrait { let mut compiler = Compiler { opcodes: Default::default() }; // Add the opcodes to the dict compiler.add_opcode('OP_0', Opcode::OP_0); - compiler.add_opcode('OP_FALSE', Opcode::OP_0); + compiler.add_opcode('OP_FALSE', Opcode::OP_FALSE); compiler.add_opcode('OP_DATA_1', Opcode::OP_DATA_1); compiler.add_opcode('OP_DATA_2', Opcode::OP_DATA_2); compiler.add_opcode('OP_DATA_3', Opcode::OP_DATA_3); @@ -286,6 +286,8 @@ pub impl CompilerImpl of CompilerTrait { compiler.add_opcode('OP_LSHIFT', Opcode::OP_LSHIFT); compiler.add_opcode('OP_RSHIFT', Opcode::OP_RSHIFT); compiler.add_opcode('OP_NOP1', Opcode::OP_NOP1); + compiler.add_opcode('OP_NOP2', Opcode::OP_NOP2); + compiler.add_opcode('OP_NOP3', Opcode::OP_NOP3); compiler.add_opcode('OP_NOP4', Opcode::OP_NOP4); compiler.add_opcode('OP_NOP5', Opcode::OP_NOP5); compiler.add_opcode('OP_NOP6', Opcode::OP_NOP6); diff --git a/packages/engine/Scarb.toml b/packages/engine/Scarb.toml index 0cd83f25..8e3c5923 100644 --- a/packages/engine/Scarb.toml +++ b/packages/engine/Scarb.toml @@ -6,7 +6,6 @@ edition = "2024_07" [dependencies] ripemd160.workspace = true sha1.workspace = true -shinigami_compiler = { path = "../compiler" } shinigami_utils = { path = "../utils" } [dev-dependencies] diff --git a/packages/engine/src/engine.cairo b/packages/engine/src/engine.cairo index c319563d..0b0e8573 100644 --- a/packages/engine/src/engine.cairo +++ b/packages/engine/src/engine.cairo @@ -1,48 +1,31 @@ use crate::cond_stack::{ConditionalStack, ConditionalStackImpl}; use crate::errors::Error; -use crate::opcodes::{flow, opcodes::Opcode}; -use crate::scriptflags::ScriptFlags; +use crate::parser; +use crate::opcodes::opcodes::Opcode; +use crate::flags::ScriptFlags; use crate::stack::{ScriptStack, ScriptStackImpl}; use crate::transaction::{ - Transaction, EngineTransactionInputTrait, EngineTransactionOutputTrait, EngineTransactionTrait + EngineTransactionInputTrait, EngineTransactionOutputTrait, EngineTransactionTrait }; -use shinigami_utils::byte_array::{byte_array_to_bool, byte_array_to_felt252_le}; +use crate::hash_cache::{HashCache, HashCacheTrait}; +use crate::witness; +use shinigami_utils::byte_array::byte_array_to_bool; use shinigami_utils::bytecode::hex_to_bytecode; use shinigami_utils::hash::sha256_byte_array; -use crate::witness; +use crate::taproot; +use crate::taproot::{TaprootContext, TaprootContextImpl, ControlBlockImpl}; -// SigCache implements an Schnorr+ECDSA signature verification cache. Only valid signatures will be -// added to the cache. -pub trait SigCacheTrait { - // Returns true if sig cache contains sig_hash corresponding to signature and public key - fn exists(sig_hash: u256, signature: ByteArray, pub_key: ByteArray) -> bool; - // Adds a signature to the cache - fn add(sig_hash: u256, signature: ByteArray, pub_key: ByteArray); -} +pub const MAX_STACK_SIZE: u32 = 1000; +pub const MAX_SCRIPT_SIZE: u32 = 10000; +pub const MAX_OPS_PER_SCRIPT: u32 = 201; +pub const MAX_SCRIPT_ELEMENT_SIZE: u32 = 520; -// HashCache caches the midstate of segwit v0 and v1 sighashes -pub trait HashCacheTrait< - H, - I, - O, - T, - +EngineTransactionInputTrait, - +EngineTransactionOutputTrait, - +EngineTransactionTrait -> { - fn new(transaction: @T) -> H; - - // v0 represents sighash midstate used in the base segwit signatures BIP-143 - fn get_hash_prevouts_v0(self: @H) -> u256; - fn get_hash_sequence_v0(self: @H) -> u256; - fn get_hash_outputs_v0(self: @H) -> u256; - - // v1 represents sighash midstate used to compute taproot signatures BIP-341 - fn get_hash_prevouts_v1(self: @H) -> u256; - fn get_hash_sequence_v1(self: @H) -> u256; - fn get_hash_outputs_v1(self: @H) -> u256; - fn get_hash_input_scripts_v1(self: @H) -> u256; -} +const BASE_SEGWIT_WITNESS_VERSION: i64 = 0; +const TAPROOT_WITNESS_VERSION: i64 = 1; + +const PAY_TO_WITNESS_PUBKEY_HASH_SIZE: u32 = 20; +const PAY_TO_WITNESS_SCRIPT_HASH_SIZE: u32 = 32; +const PAY_TO_TAPROOT_DATA_SIZE: u32 = 32; // Represents the VM that executes Bitcoin scripts #[derive(Destruct)] @@ -52,7 +35,7 @@ pub struct Engine { // Is Bip16 p2sh bip16: bool, // Transaction context being executed - pub transaction: T, + pub transaction: @T, // Input index within the tx containing signature script being executed pub tx_idx: u32, // Amount of the input being spent @@ -67,12 +50,18 @@ pub struct Engine { pub witness_program: ByteArray, // The witness version pub witness_version: i64, + // The taproot context for exection + pub taproot_context: TaprootContext, + // Whether to use taproot + pub use_taproot: bool, // Primary data stack pub dstack: ScriptStack, // Alternate data stack pub astack: ScriptStack, // Tracks conditonal execution state supporting nested conditionals pub cond_stack: ConditionalStack, + // Copy of the stack from 1st script in a P2SH exec + pub saved_first_stack: Span, // Position within script of last OP_CODESEPARATOR pub last_code_sep: u32, // Count number of non-push opcodes @@ -81,15 +70,13 @@ pub struct Engine { // TODO: SigCache pub trait EngineTrait< - E, I, O, T, - H, +EngineTransactionInputTrait, +EngineTransactionOutputTrait, +EngineTransactionTrait, - +HashCacheTrait + +HashCacheTrait > { // Create a new Engine with the given script fn new( @@ -98,24 +85,27 @@ pub trait EngineTrait< tx_idx: u32, flags: u32, amount: i64, - hash_cache: @H - ) -> Result; + hash_cache: @HashCache + ) -> Result, felt252>; + // Executes a single step of the script, returning true if more steps are needed + fn step(ref self: Engine) -> Result; // Executes the entire script and returns top of stack or error if script fails - fn execute(ref self: E) -> Result; + fn execute(ref self: Engine) -> Result; } pub impl EngineImpl< I, O, T, - H, impl IEngineTransactionInput: EngineTransactionInputTrait, impl IEngineTransactionOutput: EngineTransactionOutputTrait, impl IEngineTransaction: EngineTransactionTrait< T, I, O, IEngineTransactionInput, IEngineTransactionOutput >, - impl IHashCache: HashCacheTrait, -> of EngineTrait, I, O, T, H> { + +Drop, + +Drop, + +Drop, +> of EngineTrait { // Create a new Engine with the given script fn new( script_pubkey: @ByteArray, @@ -123,142 +113,20 @@ pub impl EngineImpl< tx_idx: u32, flags: u32, amount: i64, - hash_cache: @H + hash_cache: @HashCache ) -> Result, felt252> { - let _ = transaction.get_transaction_inputs(); - return Result::Err('todo'); - } - - // Executes the entire script and returns top of stack or error if script fails - fn execute(ref self: Engine) -> Result { - // TODO - Result::Ok("0") - } -} - -pub trait EngineExtrasTrait { - // Pulls the next len bytes from the script and advances the program counter - fn pull_data(ref self: Engine, len: usize) -> Result; - // Return true if the script engine instance has the specified flag set. - fn has_flag(ref self: Engine, flag: ScriptFlags) -> bool; - // Pop bool enforcing minimal if - fn pop_if_bool(ref self: Engine) -> Result; - // Return true if the witness program was active - fn is_witness_active(ref self: Engine, version: i64) -> bool; - // Return the script since last OP_CODESEPARATOR - fn sub_script(ref self: Engine) -> ByteArray; -} - -pub impl EngineExtrasImpl> of EngineExtrasTrait { - fn pull_data(ref self: Engine, len: usize) -> Result { - let mut data = ""; - let mut i = self.opcode_idx + 1; - let mut end = i + len; - let script = *(self.scripts[self.script_idx]); - if end > script.len() { - return Result::Err(Error::SCRIPT_INVALID); - } - while i != end { - data.append_byte(script[i]); - i += 1; - }; - self.opcode_idx = end - 1; - return Result::Ok(data); - } - - fn has_flag(ref self: Engine, flag: ScriptFlags) -> bool { - self.flags & flag.into() == flag.into() - } - - fn pop_if_bool(ref self: Engine) -> Result { - if !self.is_witness_active(0) || !self.has_flag(ScriptFlags::ScriptVerifyMinimalIf) { - return self.dstack.pop_bool(); - } - let top = self.dstack.pop_byte_array()?; - if top.len() > 1 { - return Result::Err(Error::MINIMAL_IF); - } - - if top.len() == 1 && top[0] != 0x01 { - return Result::Err(Error::MINIMAL_IF); - } - return Result::Ok(byte_array_to_bool(@top)); - } - - fn is_witness_active(ref self: Engine, version: i64) -> bool { - return self.witness_version == version && self.witness_program.len() != 0; - } - - fn sub_script(ref self: Engine) -> ByteArray { - let script = *(self.scripts[self.script_idx]); - if self.last_code_sep == 0 { - return script.clone(); - } - - let mut sub_script = ""; - let mut i = self.last_code_sep; - while i != script.len() { - sub_script.append_byte(script[i]); - i += 1; - }; - return sub_script; - } -} - -pub trait EngineInternalTrait { - // Create a new Engine with the given script - fn new( - script_pubkey: @ByteArray, transaction: Transaction, tx_idx: u32, flags: u32, amount: i64 - ) -> Result, felt252>; - // Returns true if the script is a script hash - fn is_script_hash(ref self: Engine) -> bool; - // Returns true if the script sig is push only - fn is_push_only(ref self: Engine) -> bool; - // Pulls the next len bytes from the script at the given index - fn pull_data_at( - ref self: Engine, idx: usize, len: usize - ) -> Result; - fn get_dstack(ref self: Engine) -> Span; - fn get_astack(ref self: Engine) -> Span; - // Returns the length of the next push data opcode - fn push_data_len(ref self: Engine, opcode: u8, idx: u32) -> Result; - // Skip the next opcode if it is a push opcode in unexecuted conditional branch - fn skip_push_data(ref self: Engine, opcode: u8) -> Result<(), felt252>; - // Executes the next instruction in the script - fn step(ref self: Engine) -> Result; - // Executes the entire script and returns top of stack or error if script fails - fn execute(ref self: Engine) -> Result; - // Validate witness program using witness input - fn verify_witness( - ref self: Engine, witness: Span - ) -> Result<(), felt252>; - // Ensure the stack size is within limits - fn check_stack_size(ref self: Engine) -> Result<(), felt252>; - // Check if the next opcode is a minimal push - fn check_minimal_data_push(ref self: Engine, opcode: u8) -> Result<(), felt252>; - // Print engine data as a JSON object - fn json(ref self: Engine); -} - -pub const MAX_STACK_SIZE: u32 = 1000; -pub const MAX_SCRIPT_SIZE: u32 = 10000; -pub const MAX_OPS_PER_SCRIPT: u32 = 201; -pub const MAX_SCRIPT_ELEMENT_SIZE: u32 = 520; - -pub impl EngineInternalImpl of EngineInternalTrait { - fn new( - script_pubkey: @ByteArray, transaction: Transaction, tx_idx: u32, flags: u32, amount: i64 - ) -> Result, felt252> { - if tx_idx >= transaction.transaction_inputs.len() { + let transaction_inputs = transaction.get_transaction_inputs(); + if tx_idx >= transaction_inputs.len() { return Result::Err('Engine::new: tx_idx invalid'); } - let script_sig = transaction.transaction_inputs[tx_idx].signature_script; + let tx_input = transaction_inputs[tx_idx]; + let script_sig = tx_input.get_signature_script(); if script_sig.len() == 0 && script_pubkey.len() == 0 { return Result::Err(Error::SCRIPT_EMPTY_STACK); } - let witness_len = transaction.transaction_inputs[tx_idx].witness.len(); + let witness_len = tx_input.get_witness().len(); let mut engine = Engine { flags: flags, bip16: false, @@ -270,9 +138,12 @@ pub impl EngineInternalImpl of EngineInternalTrait { opcode_idx: 0, witness_program: "", witness_version: 0, + taproot_context: TaprootContextImpl::empty(), + use_taproot: false, dstack: ScriptStackImpl::new(), astack: ScriptStackImpl::new(), cond_stack: ConditionalStackImpl::new(), + saved_first_stack: array![].span(), last_code_sep: 0, num_ops: 0, }; @@ -283,13 +154,15 @@ pub impl EngineInternalImpl of EngineInternalTrait { return Result::Err('Engine::new: invalid flag combo'); } - if engine.has_flag(ScriptFlags::ScriptVerifySigPushOnly) && !engine.is_push_only() { + if engine.has_flag(ScriptFlags::ScriptVerifySigPushOnly) + && !parser::is_push_only(script_sig) { return Result::Err('Engine::new: not pushonly'); } let mut bip16 = false; - if engine.has_flag(ScriptFlags::ScriptBip16) && engine.is_script_hash() { - if !engine.has_flag(ScriptFlags::ScriptVerifySigPushOnly) && !engine.is_push_only() { + if engine.has_flag(ScriptFlags::ScriptBip16) && parser::is_script_hash(script_pubkey) { + if !engine.has_flag(ScriptFlags::ScriptVerifySigPushOnly) + && !parser::is_push_only(script_sig) { return Result::Err('Engine::new: p2sh not pushonly'); } engine.bip16 = true; @@ -298,7 +171,8 @@ pub impl EngineInternalImpl of EngineInternalTrait { let mut i = 0; let mut valid_sizes = true; - while i != engine.scripts.len() { + let scripts_len = engine.scripts.len(); + while i != scripts_len { let script = *(engine.scripts[i]); if script.len() > MAX_SCRIPT_SIZE { valid_sizes = false; @@ -328,17 +202,18 @@ pub impl EngineInternalImpl of EngineInternalTrait { let mut witness_program: ByteArray = ""; if witness::is_witness_program(script_pubkey) { if script_sig.len() != 0 { - return Result::Err('Engine::new: witness w/ sig'); + return Result::Err(Error::WITNESS_MALLEATED); } witness_program = script_pubkey.clone(); } else if witness_len != 0 && bip16 { - let sig_clone = engine.scripts[0].clone(); + let sig_clone = script_sig.clone(); if sig_clone.len() > 2 { let first_elem = sig_clone[0]; let mut remaining = ""; let mut i = 1; // TODO: Optimize - while i != sig_clone.len() { + let sig_len = sig_clone.len(); + while i != sig_len { remaining.append_byte(sig_clone[i]); i += 1; }; @@ -346,10 +221,10 @@ pub impl EngineInternalImpl of EngineInternalTrait { && witness::is_witness_program(@remaining) { witness_program = remaining; } else { - return Result::Err('Engine::new: sig malleability'); + return Result::Err(Error::WITNESS_MALLEATED_P2SH); } } else { - return Result::Err('Engine::new: sig malleability'); + return Result::Err(Error::WITNESS_MALLEATED_P2SH); } } @@ -360,101 +235,15 @@ pub impl EngineInternalImpl of EngineInternalTrait { engine.witness_version = witness_version; engine.witness_program = witness_program; } else if engine.witness_program.len() == 0 && witness_len != 0 { - return Result::Err('Engine::new: witness + no prog'); + return Result::Err(Error::WITNESS_UNEXPECTED); } } return Result::Ok(engine); } - fn is_script_hash(ref self: Engine) -> bool { - let script_pubkey = *(self.scripts[1]); - if script_pubkey.len() == 23 - && script_pubkey[0] == Opcode::OP_HASH160 - && script_pubkey[1] == Opcode::OP_DATA_20 - && script_pubkey[22] == Opcode::OP_EQUAL { - return true; - } - return false; - } - - fn is_push_only(ref self: Engine) -> bool { - let script: @ByteArray = *(self.scripts[0]); - let mut i = 0; - let mut is_push_only = true; - while i != script.len() { - // TODO: Error handling if i outside bounds - let opcode = script[i]; - if opcode > Opcode::OP_16 { - is_push_only = false; - break; - } - - // TODO: Error handling - let data_len = Opcode::data_len(i, script).unwrap(); - i += data_len + 1; - }; - return is_push_only; - } - - fn pull_data_at( - ref self: Engine, idx: usize, len: usize - ) -> Result { - let mut data = ""; - let mut i = idx; - let mut end = i + len; - let script = *(self.scripts[self.script_idx]); - if end > script.len() { - return Result::Err(Error::SCRIPT_INVALID); - } - while i != end { - data.append_byte(script[i]); - i += 1; - }; - return Result::Ok(data); - } - - fn get_dstack(ref self: Engine) -> Span { - return self.dstack.stack_to_span(); - } - - fn get_astack(ref self: Engine) -> Span { - return self.astack.stack_to_span(); - } - - fn push_data_len( - ref self: Engine, opcode: u8, idx: u32 - ) -> Result { - if opcode == Opcode::OP_PUSHDATA1 { - return Result::Ok( - byte_array_to_felt252_le(@self.pull_data_at(idx + 1, 1)?).try_into().unwrap() - ); - } else if opcode == Opcode::OP_PUSHDATA2 { - return Result::Ok( - byte_array_to_felt252_le(@self.pull_data_at(idx + 1, 2)?).try_into().unwrap() - ); - } else if opcode == Opcode::OP_PUSHDATA4 { - return Result::Ok( - byte_array_to_felt252_le(@self.pull_data_at(idx + 1, 4)?).try_into().unwrap() - ); - } - return Result::Err('Engine::push_data_len: invalid'); - } - - fn skip_push_data(ref self: Engine, opcode: u8) -> Result<(), felt252> { - if opcode == Opcode::OP_PUSHDATA1 { - self.opcode_idx += self.push_data_len(opcode, self.opcode_idx)? + 2; - } else if opcode == Opcode::OP_PUSHDATA2 { - self.opcode_idx += self.push_data_len(opcode, self.opcode_idx)? + 3; - } else if opcode == Opcode::OP_PUSHDATA4 { - self.opcode_idx += self.push_data_len(opcode, self.opcode_idx)? + 5; - } else { - return Result::Err(Error::SCRIPT_INVALID); - } - Result::Ok(()) - } - - fn step(ref self: Engine) -> Result { + fn step(ref self: Engine) -> Result { + // TODO: Make it match engine.execute after recent changes if self.script_idx >= self.scripts.len() { return Result::Ok(false); } @@ -480,25 +269,9 @@ pub impl EngineInternalImpl of EngineInternalTrait { return Result::Err(illegal_opcode.unwrap_err()); } - if !self.cond_stack.branch_executing() && !flow::is_branching_opcode(opcode) { - if Opcode::is_data_opcode(opcode) { - let opcode_32: u32 = opcode.into(); - self.opcode_idx += opcode_32 + 1; - return Result::Ok(true); - } else if Opcode::is_push_opcode(opcode) { - let res = self.skip_push_data(opcode); - if res.is_err() { - return Result::Err(res.unwrap_err()); - } - return Result::Ok(true); - } else { - let res = Opcode::is_opcode_disabled(opcode, ref self); - if res.is_err() { - return Result::Err(res.unwrap_err()); - } - self.opcode_idx += 1; - return Result::Ok(true); - } + if !self.cond_stack.branch_executing() && !Opcode::is_branching_opcode(opcode) { + self.skip()?; + return Result::Ok(true); } if self.dstack.verify_minimal_data @@ -529,14 +302,22 @@ pub impl EngineInternalImpl of EngineInternalTrait { return Result::Ok(true); } - fn execute(ref self: Engine) -> Result { + // Executes the entire script and returns top of stack or error if script fails + fn execute(ref self: Engine) -> Result { let mut err = ''; // TODO: Optimize with != instead of < and check for bounds errors within the loop while self.script_idx < self.scripts.len() { let script: @ByteArray = *self.scripts[self.script_idx]; - while self.opcode_idx < script.len() { - let opcode = script[self.opcode_idx]; + let script_len = script.len(); + if script_len == 0 { + self.script_idx += 1; + continue; + } + while self.opcode_idx < script_len { + let opcode_idx = self.opcode_idx; + let opcode = script[opcode_idx]; + // TODO: Can this be defered to opcode execution like disabled // Check if the opcode is always illegal (reserved). let illegal_opcode = Opcode::is_opcode_always_illegal(opcode, ref self); if illegal_opcode.is_err() { @@ -544,14 +325,14 @@ pub impl EngineInternalImpl of EngineInternalTrait { break; } - if opcode > Opcode::OP_16 { + if !self.use_taproot && opcode > Opcode::OP_16 { self.num_ops += 1; if self.num_ops > MAX_OPS_PER_SCRIPT { err = Error::SCRIPT_TOO_MANY_OPERATIONS; break; } } else if Opcode::is_push_opcode(opcode) { - let res = self.push_data_len(opcode, self.opcode_idx); + let res = parser::push_data_len(script, opcode_idx); if res.is_err() { err = res.unwrap_err(); break; @@ -562,27 +343,13 @@ pub impl EngineInternalImpl of EngineInternalTrait { } } - if !self.cond_stack.branch_executing() && !flow::is_branching_opcode(opcode) { - if Opcode::is_data_opcode(opcode) { - let opcode_32: u32 = opcode.into(); - self.opcode_idx += opcode_32 + 1; - continue; - } else if Opcode::is_push_opcode(opcode) { - let res = self.skip_push_data(opcode); - if res.is_err() { - err = res.unwrap_err(); - break; - } - continue; - } else { - let res = Opcode::is_opcode_disabled(opcode, ref self); - if res.is_err() { - err = res.unwrap_err(); - break; - } - self.opcode_idx += 1; - continue; + if !self.cond_stack.branch_executing() && !Opcode::is_branching_opcode(opcode) { + let res = self.skip(); + if res.is_err() { + err = res.unwrap_err(); + break; } + continue; } if self.dstack.verify_minimal_data @@ -611,7 +378,7 @@ pub impl EngineInternalImpl of EngineInternalTrait { if err != '' { break; } - if self.cond_stack.len() > 0 { + if self.cond_stack.len() != 0 { err = Error::SCRIPT_UNBALANCED_CONDITIONAL_STACK; break; } @@ -621,11 +388,29 @@ pub impl EngineInternalImpl of EngineInternalTrait { } self.num_ops = 0; self.opcode_idx = 0; - if (self.script_idx == 1 && self.witness_program.len() != 0) + if self.script_idx == 0 && self.bip16 { + self.script_idx += 1; + // TODO: Use @ instead of clone span + self.saved_first_stack = self.dstack.stack_to_span(); + } else if self.script_idx == 1 && self.bip16 { + self.script_idx += 1; + + let res = self.check_error_condition(false); + if res.is_err() { + err = res.unwrap_err(); + break; + } + let saved_stack_len = self.saved_first_stack.len(); + let redeem_script = self.saved_first_stack[saved_stack_len - 1]; + // TODO: check script parses? + self.scripts.append(redeem_script); + self.dstack.set_stack(self.saved_first_stack, 0, saved_stack_len - 1); + } else if (self.script_idx == 1 && self.witness_program.len() != 0) || (self.script_idx == 2 && self.witness_program.len() != 0 && self.bip16) { self.script_idx += 1; - let witness = self.transaction.transaction_inputs[self.tx_idx].witness; - let res = self.verify_witness(witness.span()); + let tx_input = self.transaction.get_transaction_inputs()[self.tx_idx]; + let witness = tx_input.get_witness(); + let res = self.verify_witness(witness); if res.is_err() { err = res.unwrap_err(); break; @@ -640,46 +425,174 @@ pub impl EngineInternalImpl of EngineInternalTrait { return Result::Err(err); } - // TODO: CheckErrorCondition - if self.is_witness_active(0) && self.dstack.len() != 1 { // TODO: Hardcoded 0 - return Result::Err(Error::SCRIPT_NON_CLEAN_STACK); + return self.check_error_condition(true); + } +} + +// TODO: Remove functions that can be locally used only +pub trait EngineInternalTrait< + I, + O, + T, + +EngineTransactionInputTrait, + +EngineTransactionOutputTrait, + +EngineTransactionTrait, + +HashCacheTrait, +> { + // Pulls the next len bytes from the script and advances the program counter + fn pull_data(ref self: Engine, len: usize) -> Result; + // Return true if the script engine instance has the specified flag set. + fn has_flag(ref self: Engine, flag: ScriptFlags) -> bool; + // Pop bool enforcing minimal if + fn pop_if_bool(ref self: Engine) -> Result; + // Return true if the witness program was active + fn is_witness_active(ref self: Engine, version: i64) -> bool; + // Return the script since last OP_CODESEPARATOR + fn sub_script(ref self: Engine) -> ByteArray; + // Returns the data stack + fn get_dstack(ref self: Engine) -> Span; + // Returns the alt stack + fn get_astack(ref self: Engine) -> Span; + // Skips the next opcode in execution based on execution rules + fn skip(ref self: Engine) -> Result<(), felt252>; + // Ensure the stack size is within limits + fn check_stack_size(ref self: Engine) -> Result<(), felt252>; + // Check if the next opcode is a minimal push + fn check_minimal_data_push(ref self: Engine, opcode: u8) -> Result<(), felt252>; + // Validate witness program using witness input + fn verify_witness(ref self: Engine, witness: Span) -> Result<(), felt252>; + // Check if the script has failed and return an error if it has + fn check_error_condition(ref self: Engine, final: bool) -> Result; + // Prints the engine state as json + fn json(ref self: Engine); +} + +pub impl EngineInternalImpl< + I, + O, + T, + impl IEngineTransactionInput: EngineTransactionInputTrait, + impl IEngineTransactionOutput: EngineTransactionOutputTrait, + impl IEngineTransaction: EngineTransactionTrait< + T, I, O, IEngineTransactionInput, IEngineTransactionOutput + >, + +Drop, + +Drop, + +Drop, +> of EngineInternalTrait { + fn pull_data(ref self: Engine, len: usize) -> Result { + let script = *(self.scripts[self.script_idx]); + let data = parser::data_at(script, self.opcode_idx + 1, len)?; + self.opcode_idx += len; + return Result::Ok(data); + } + + fn has_flag(ref self: Engine, flag: ScriptFlags) -> bool { + self.flags & flag.into() == flag.into() + } + + fn pop_if_bool(ref self: Engine) -> Result { + if !self.is_witness_active(0) || !self.has_flag(ScriptFlags::ScriptVerifyMinimalIf) { + return self.dstack.pop_bool(); } - if self.has_flag(ScriptFlags::ScriptVerifyCleanStack) && self.dstack.len() != 1 { - return Result::Err(Error::SCRIPT_NON_CLEAN_STACK); + let top = self.dstack.pop_byte_array()?; + if top.len() > 1 { + return Result::Err(Error::MINIMAL_IF); } - if self.dstack.len() < 1 { - return Result::Err(Error::SCRIPT_EMPTY_STACK); - } else { - // TODO: pop bool? - let top_stack = self.dstack.peek_byte_array(0)?; - let ret_val = top_stack.clone(); - let mut is_ok = false; - let mut i = 0; - while i != top_stack.len() { - if top_stack[i] != 0 { - is_ok = true; - break; - } - i += 1; - }; - if is_ok { - return Result::Ok(ret_val); - } else { - return Result::Err(Error::SCRIPT_FAILED); + if top.len() == 1 && top[0] != 0x01 { + return Result::Err(Error::MINIMAL_IF); + } + return Result::Ok(byte_array_to_bool(@top)); + } + + fn is_witness_active(ref self: Engine, version: i64) -> bool { + return self.witness_version == version && self.witness_program.len() != 0; + } + + fn sub_script(ref self: Engine) -> ByteArray { + let script = *(self.scripts[self.script_idx]); + if self.last_code_sep == 0 { + return script.clone(); + } + + let mut sub_script = ""; + let mut i = self.last_code_sep; + let script_len = script.len(); + while i != script_len { + sub_script.append_byte(script[i]); + i += 1; + }; + return sub_script; + } + + fn get_dstack(ref self: Engine) -> Span { + return self.dstack.stack_to_span(); + } + + fn get_astack(ref self: Engine) -> Span { + return self.astack.stack_to_span(); + } + + fn skip(ref self: Engine) -> Result<(), felt252> { + let script = *(self.scripts[self.script_idx]); + let opcode = script.at(self.opcode_idx).unwrap(); + Opcode::is_opcode_disabled(opcode, ref self)?; + let next = parser::next(script, self.opcode_idx)?; + self.opcode_idx = next; + return Result::Ok(()); + } + + fn check_minimal_data_push(ref self: Engine, opcode: u8) -> Result<(), felt252> { + if opcode == Opcode::OP_0 { + return Result::Ok(()); + } + let script = *(self.scripts[self.script_idx]); + if opcode == Opcode::OP_DATA_1 { + let value: u8 = script.at(self.opcode_idx + 1).unwrap(); + if value >= 1 && value <= 16 { + // Should be OP_1 to OP_16 + return Result::Err(Error::MINIMAL_DATA); } + if value == 0x81 { + // Should be OP_1NEGATE + return Result::Err(Error::MINIMAL_DATA); + } + } + + // TODO: More checks? + if !Opcode::is_push_opcode(opcode) { + return Result::Ok(()); + } + + let len = parser::push_data_len(script, self.opcode_idx)?; + if len <= 75 { + // Should have used OP_DATA_X + return Result::Err(Error::MINIMAL_DATA); + } else if len <= 255 && opcode != Opcode::OP_PUSHDATA1 { + // Should have used OP_PUSHDATA1 + return Result::Err(Error::MINIMAL_DATA); + } else if len <= 65535 && opcode != Opcode::OP_PUSHDATA2 { + // Should have used OP_PUSHDATA2 + return Result::Err(Error::MINIMAL_DATA); + } + return Result::Ok(()); + } + + fn check_stack_size(ref self: Engine) -> Result<(), felt252> { + if self.dstack.len() + self.astack.len() > MAX_STACK_SIZE { + return Result::Err(Error::STACK_OVERFLOW); } + return Result::Ok(()); } - fn verify_witness( - ref self: Engine, witness: Span - ) -> Result<(), felt252> { + fn verify_witness(ref self: Engine, witness: Span) -> Result<(), felt252> { if self.is_witness_active(0) { // Verify a base witness (segwit) program, ie P2WSH || P2WPKH - if self.witness_program.len() == 20 { + if self.witness_program.len() == PAY_TO_WITNESS_PUBKEY_HASH_SIZE { // P2WPKH if witness.len() != 2 { - return Result::Err(Error::WITNESS_PROGRAM_INVALID); + return Result::Err(Error::WITNESS_PROGRAM_MISMATCH); } // OP_DUP OP_HASH160 OP_DATA_20 OP_EQUALVERIFY OP_CHECKSIG let mut pk_script = hex_to_bytecode(@"0x76a914"); @@ -688,10 +601,10 @@ pub impl EngineInternalImpl of EngineInternalTrait { self.scripts.append(@pk_script); self.dstack.set_stack(witness, 0, witness.len()); - } else if self.witness_program.len() == 32 { + } else if self.witness_program.len() == PAY_TO_WITNESS_SCRIPT_HASH_SIZE { // P2WSH if witness.len() == 0 { - return Result::Err(Error::WITNESS_PROGRAM_INVALID); + return Result::Err(Error::WITNESS_PROGRAM_EMPTY); } let witness_script = witness[witness.len() - 1]; if witness_script.len() > MAX_SCRIPT_SIZE { @@ -699,14 +612,84 @@ pub impl EngineInternalImpl of EngineInternalTrait { } let witness_hash = sha256_byte_array(witness_script); if witness_hash != self.witness_program { - return Result::Err(Error::WITNESS_PROGRAM_INVALID); + return Result::Err(Error::WITNESS_PROGRAM_MISMATCH); } self.scripts.append(witness_script); self.dstack.set_stack(witness, 0, witness.len() - 1); } else { + return Result::Err(Error::WITNESS_PROGRAM_WRONG_LENGTH); + } + } else if self.is_witness_active(TAPROOT_WITNESS_VERSION) + && self.witness_program.len() == PAY_TO_TAPROOT_DATA_SIZE + && !self.bip16.clone() { + // Verify a taproot witness program + if !self.has_flag(ScriptFlags::ScriptVerifyTaproot) { + return Result::Ok(()); + } + + if witness.len() == 0 { return Result::Err(Error::WITNESS_PROGRAM_INVALID); } + + self.use_taproot = true; + self + .taproot_context = + TaprootContextImpl::new(witness::serialized_witness_size(witness)); + let mut witness_len = witness.len(); + if taproot::is_annexed_witness(witness, witness_len) { + self.taproot_context.annex = witness[witness_len - 1]; + witness_len -= 1; // Remove annex + } + + if witness_len == 1 { + TaprootContextImpl::verify_taproot_spend( + @self.witness_program, witness[0], self.transaction, self.tx_idx + )?; + self.taproot_context.must_succeed = true; + return Result::Ok(()); + } else { + let control_block = taproot::parse_control_block(witness[witness_len - 1])?; + let witness_script = witness[witness_len - 2]; + control_block.verify_taproot_leaf(@self.witness_program, witness_script)?; + + if Opcode::has_success_opcode(witness_script) { + if self.has_flag(ScriptFlags::ScriptVerifyDiscourageOpSuccess) { + return Result::Err(Error::DISCOURAGE_OP_SUCCESS); + } + + self.taproot_context.must_succeed = true; + return Result::Ok(()); + } + + if control_block.leaf_version != taproot::BASE_LEAF_VERSION { + if self.has_flag(ScriptFlags::ScriptVerifyDiscourageUpgradeableTaprootVersion) { + return Result::Err(Error::DISCOURAGE_UPGRADABLE_TAPROOT_VERSION); + } else { + self.taproot_context.must_succeed = true; + return Result::Ok(()); + } + } + + self + .taproot_context + .tapleaf_hash = taproot::tap_hash(witness_script, taproot::BASE_LEAF_VERSION); + self.scripts.append(witness_script); + self.dstack.set_stack(witness, 0, witness_len - 2); + } + } else if self.has_flag(ScriptFlags::ScriptVerifyDiscourageUpgradeableWitnessProgram) { + return Result::Err(Error::DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM); + } else { + self.witness_program = ""; + } + + if self.is_witness_active(TAPROOT_WITNESS_VERSION) { + if self.dstack.len() > MAX_STACK_SIZE { + return Result::Err(Error::STACK_OVERFLOW); + } + } + if self.is_witness_active(BASE_SEGWIT_WITNESS_VERSION) + || self.is_witness_active(TAPROOT_WITNESS_VERSION) { // Sanity checks let mut err = ''; for w in self @@ -720,62 +703,39 @@ pub impl EngineInternalImpl of EngineInternalTrait { if err != '' { return Result::Err(err); } - } else if self.is_witness_active(1) { - // Verify a taproot witness program - // TODO: Implement - return Result::Err('Taproot not implemented'); - } else if self.has_flag(ScriptFlags::ScriptVerifyDiscourageUpgradeableWitnessProgram) { - return Result::Err(Error::DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM); - } else { - self.witness_program = ""; } - return Result::Ok(()); } - fn check_stack_size(ref self: Engine) -> Result<(), felt252> { - if self.dstack.len() + self.astack.len() > MAX_STACK_SIZE { - return Result::Err(Error::STACK_OVERFLOW); + fn check_error_condition(ref self: Engine, final: bool) -> Result { + // Check if execution is actually done + if self.script_idx < self.scripts.len() { + return Result::Err(Error::SCRIPT_UNFINISHED); } - return Result::Ok(()); - } - fn check_minimal_data_push(ref self: Engine, opcode: u8) -> Result<(), felt252> { - if opcode == Opcode::OP_0 { - return Result::Ok(()); - } - let script = *(self.scripts[self.script_idx]); - if opcode == Opcode::OP_DATA_1 { - let value: u8 = script.at(self.opcode_idx + 1).unwrap(); - if value <= 16 { - // Should be OP_1 to OP_16 - return Result::Err(Error::MINIMAL_DATA); - } - if value == 0x81 { - // Should be OP_1NEGATE - return Result::Err(Error::MINIMAL_DATA); - } + // Check if witness stack is clean + if final && self.is_witness_active(0) && self.dstack.len() != 1 { // TODO: Hardcoded 0 + return Result::Err(Error::SCRIPT_NON_CLEAN_STACK); } - // TODO: More checks? - if !Opcode::is_push_opcode(opcode) { - return Result::Ok(()); + if final && self.has_flag(ScriptFlags::ScriptVerifyCleanStack) && self.dstack.len() != 1 { + return Result::Err(Error::SCRIPT_NON_CLEAN_STACK); } - let len = self.push_data_len(opcode, self.opcode_idx)?; - if len <= 75 { - // Should have used OP_DATA_X - return Result::Err(Error::MINIMAL_DATA); - } else if len <= 255 && opcode != Opcode::OP_PUSHDATA1 { - // Should have used OP_PUSHDATA1 - return Result::Err(Error::MINIMAL_DATA); - } else if len <= 65535 && opcode != Opcode::OP_PUSHDATA2 { - // Should have used OP_PUSHDATA2 - return Result::Err(Error::MINIMAL_DATA); + // Check if stack has at least one item + if self.dstack.len() == 0 { + return Result::Err(Error::SCRIPT_EMPTY_STACK); + } else { + // Check the final stack value + let is_ok = self.dstack.peek_bool(0)?; + if is_ok { + return Result::Ok(self.dstack.peek_byte_array(0)?); + } else { + return Result::Err(Error::SCRIPT_FAILED); + } } - return Result::Ok(()); } - fn json(ref self: Engine) { + fn json(ref self: Engine) { self.dstack.json(); } } diff --git a/packages/engine/src/errors.cairo b/packages/engine/src/errors.cairo index 447347c6..fb75a47a 100644 --- a/packages/engine/src/errors.cairo +++ b/packages/engine/src/errors.cairo @@ -25,7 +25,26 @@ pub mod Error { pub const MINIMAL_IF: felt252 = 'If conditional must be 0 or 1'; pub const DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM: felt252 = 'Upgradable witness program'; pub const WITNESS_PROGRAM_INVALID: felt252 = 'Invalid witness program'; + pub const WITNESS_PROGRAM_MISMATCH: felt252 = 'Witness program mismatch'; + pub const WITNESS_UNEXPECTED: felt252 = 'Unexpected witness data'; + pub const WITNESS_MALLEATED: felt252 = 'Witness program with sig script'; + pub const WITNESS_MALLEATED_P2SH: felt252 = 'Signature script for p2sh wit'; + pub const WITNESS_PUBKEYTYPE: felt252 = 'Non-compressed key post-segwit'; + pub const WITNESS_PROGRAM_WRONG_LENGTH: felt252 = 'Witness program wrong length'; + pub const WITNESS_PROGRAM_EMPTY: felt252 = 'Empty witness program'; pub const SCRIPT_TOO_LARGE: felt252 = 'Script is too large'; + pub const CODESEPARATOR_NON_SEGWIT: felt252 = 'CODESEPARATOR in non-segwit'; + pub const TAPROOT_MULTISIG: felt252 = 'Multisig in taproot script'; + pub const TAPROOT_EMPTY_PUBKEY: felt252 = 'Empty pubkey in taproot script'; + pub const TAPROOT_INVALID_CONTROL_BLOCK: felt252 = 'Invalid control block'; + pub const TAPROOT_INVALID_SIG: felt252 = 'Invalid signature in tap script'; + pub const TAPROOT_PARITY_MISMATCH: felt252 = 'Parity mismatch in tap script'; + pub const TAPROOT_INVALID_MERKLE_PROOF: felt252 = 'Invalid taproot merkle proof'; + pub const DISCOURAGE_OP_SUCCESS: felt252 = 'OP_SUCCESS is discouraged'; + pub const DISCOURAGE_UPGRADABLE_TAPROOT_VERSION: felt252 = 'Upgradable taproot version'; + pub const TAPROOT_SIGOPS_EXCEEDED: felt252 = 'Taproot sigops exceeded'; + pub const SCRIPT_UNFINISHED: felt252 = 'Script unfinished'; + pub const SCRIPT_ERR_SIG_DER: felt252 = 'Signature DER error'; } pub fn byte_array_err(err: felt252) -> ByteArray { diff --git a/packages/engine/src/scriptflags.cairo b/packages/engine/src/flags.cairo similarity index 100% rename from packages/engine/src/scriptflags.cairo rename to packages/engine/src/flags.cairo diff --git a/packages/engine/src/hash_cache.cairo b/packages/engine/src/hash_cache.cairo new file mode 100644 index 00000000..1eef18a7 --- /dev/null +++ b/packages/engine/src/hash_cache.cairo @@ -0,0 +1,145 @@ +use crate::transaction::{ + EngineTransactionInputTrait, EngineTransactionOutputTrait, EngineTransactionTrait +}; +use shinigami_utils::bytecode::int_size_in_bytes; +use shinigami_utils::hash::double_sha256; + +#[derive(Clone, Copy, Drop)] +pub struct SegwitSigHashMidstate { + pub hash_prevouts_v0: u256, + pub hash_sequence_v0: u256, + pub hash_outputs_v0: u256 +} + +pub trait SigHashMidstateTrait< + I, + O, + T, + +EngineTransactionInputTrait, + +EngineTransactionOutputTrait, + +EngineTransactionTrait +> { + fn new(transaction: @T) -> SegwitSigHashMidstate; +} + +pub impl SigHashMidstateImpl< + I, + O, + T, + impl IEngineTransactionInput: EngineTransactionInputTrait, + impl IEngineTransactionOutput: EngineTransactionOutputTrait, + impl IEngineTransaction: EngineTransactionTrait< + T, I, O, IEngineTransactionInput, IEngineTransactionOutput + > +> of SigHashMidstateTrait { + fn new(transaction: @T) -> SegwitSigHashMidstate { + let mut prevouts_v0_bytes: ByteArray = ""; + let inputs = transaction.get_transaction_inputs(); + for input in inputs { + let txid = input.get_prevout_txid(); + prevouts_v0_bytes.append_word(txid.high.into(), 16); + prevouts_v0_bytes.append_word(txid.low.into(), 16); + prevouts_v0_bytes.append_word_rev(input.get_prevout_vout().into(), 4); + }; + let mut sequence_v0_bytes: ByteArray = ""; + for input in inputs { + sequence_v0_bytes.append_word_rev(input.get_sequence().into(), 4); + }; + let mut outputs_v0_bytes: ByteArray = ""; + let outputs = transaction.get_transaction_outputs(); + for output in outputs { + outputs_v0_bytes.append_word_rev(output.get_value().into(), 8); + outputs_v0_bytes + .append_word_rev( + output.get_publickey_script().len().into(), + int_size_in_bytes(output.get_publickey_script().len()) + ); + outputs_v0_bytes.append(output.get_publickey_script()); + }; + SegwitSigHashMidstate { + hash_prevouts_v0: double_sha256(@prevouts_v0_bytes), + hash_sequence_v0: double_sha256(@sequence_v0_bytes), + hash_outputs_v0: double_sha256(@outputs_v0_bytes) + } + } +} + +// SigCache implements an Schnorr+ECDSA signature verification cache. Only valid signatures will be +// added to the cache. +pub trait SigCacheTrait { + // Returns true if sig cache contains sig_hash corresponding to signature and public key + fn exists(sig_hash: u256, signature: ByteArray, pub_key: ByteArray) -> bool; + // Adds a signature to the cache + fn add(sig_hash: u256, signature: ByteArray, pub_key: ByteArray); +} + +// TODO +#[derive(Drop)] +pub struct HashCache {} + +// HashCache caches the midstate of segwit v0 and v1 sighashes +pub trait HashCacheTrait< + I, + O, + T, + +EngineTransactionInputTrait, + +EngineTransactionOutputTrait, + +EngineTransactionTrait +> { + fn new(transaction: @T) -> HashCache; + + // v0 represents sighash midstate used in the base segwit signatures BIP-143 + fn get_hash_prevouts_v0(self: @HashCache) -> u256; + fn get_hash_sequence_v0(self: @HashCache) -> u256; + fn get_hash_outputs_v0(self: @HashCache) -> u256; + + // v1 represents sighash midstate used to compute taproot signatures BIP-341 + fn get_hash_prevouts_v1(self: @HashCache) -> u256; + fn get_hash_sequence_v1(self: @HashCache) -> u256; + fn get_hash_outputs_v1(self: @HashCache) -> u256; + fn get_hash_input_scripts_v1(self: @HashCache) -> u256; +} + + +pub impl HashCacheImpl< + I, + O, + T, + impl IEngineTransactionInput: EngineTransactionInputTrait, + impl IEngineTransactionOutput: EngineTransactionOutputTrait, + impl IEngineTransaction: EngineTransactionTrait< + T, I, O, IEngineTransactionInput, IEngineTransactionOutput + > +> of HashCacheTrait { + fn new(transaction: @T) -> HashCache { + HashCache {} + } + + fn get_hash_prevouts_v0(self: @HashCache) -> u256 { + 0 + } + + fn get_hash_sequence_v0(self: @HashCache) -> u256 { + 0 + } + + fn get_hash_outputs_v0(self: @HashCache) -> u256 { + 0 + } + + fn get_hash_prevouts_v1(self: @HashCache) -> u256 { + 0 + } + + fn get_hash_sequence_v1(self: @HashCache) -> u256 { + 0 + } + + fn get_hash_outputs_v1(self: @HashCache) -> u256 { + 0 + } + + fn get_hash_input_scripts_v1(self: @HashCache) -> u256 { + 0 + } +} diff --git a/packages/engine/src/lib.cairo b/packages/engine/src/lib.cairo index d7a0fab3..8ab98940 100644 --- a/packages/engine/src/lib.cairo +++ b/packages/engine/src/lib.cairo @@ -1,9 +1,10 @@ pub mod engine; +pub mod parser; pub mod stack; pub mod cond_stack; -pub mod validate; -pub mod utxo; pub mod witness; +pub mod taproot; +pub mod hash_cache; pub mod errors; pub mod opcodes { pub mod opcodes; @@ -16,38 +17,22 @@ pub mod opcodes { pub mod arithmetic; pub mod crypto; pub mod utils; - #[cfg(test)] - mod tests { - mod test_constants; - mod test_flow; - mod test_locktime; - mod test_stack; - mod test_splice; - mod test_bitwise; - mod test_arithmetic; - mod test_crypto; - mod test_reserved; - mod test_disabled; - mod utils; - } pub use opcodes::Opcode; } pub mod scriptnum; pub use scriptnum::ScriptNum; -pub mod scriptflags; +pub mod flags; pub mod signature { pub mod signature; pub mod sighash; pub mod constants; pub mod utils; - pub use signature::{BaseSigVerifier, BaseSigVerifierTrait}; + pub use signature::{ + BaseSigVerifier, BaseSigVerifierTrait, TaprootSigVerifier, TaprootSigVerifierTrait + }; } pub mod transaction; #[cfg(test)] mod tests { - mod test_coinbase; - mod test_transactions; mod test_scriptnum; - mod test_p2pk; - mod test_p2pkh; } diff --git a/packages/engine/src/opcodes/constants.cairo b/packages/engine/src/opcodes/constants.cairo index adbb7b16..ca6ff4d3 100644 --- a/packages/engine/src/opcodes/constants.cairo +++ b/packages/engine/src/opcodes/constants.cairo @@ -1,4 +1,7 @@ -use crate::engine::{Engine, EngineExtrasTrait}; +use crate::engine::{Engine, EngineInternalTrait}; +use crate::transaction::{ + EngineTransactionTrait, EngineTransactionInputTrait, EngineTransactionOutputTrait +}; use crate::stack::ScriptStackTrait; use shinigami_utils::byte_array::byte_array_to_felt252_le; @@ -7,14 +10,42 @@ pub fn opcode_false>(ref engine: Engine) -> Result<(), felt252> { return Result::Ok(()); } -pub fn opcode_push_data>(n: usize, ref engine: Engine) -> Result<(), felt252> { - let data = EngineExtrasTrait::::pull_data(ref engine, n)?; +pub fn opcode_push_data< + T, + +Drop, + I, + +Drop, + impl IEngineTransactionInputTrait: EngineTransactionInputTrait, + O, + +Drop, + impl IEngineTransactionOutputTrait: EngineTransactionOutputTrait, + impl IEngineTransactionTrait: EngineTransactionTrait< + T, I, O, IEngineTransactionInputTrait, IEngineTransactionOutputTrait + > +>( + n: usize, ref engine: Engine +) -> Result<(), felt252> { + let data = EngineInternalTrait::::pull_data(ref engine, n)?; engine.dstack.push_byte_array(data); return Result::Ok(()); } -pub fn opcode_push_data_x>(n: usize, ref engine: Engine) -> Result<(), felt252> { - let data_len_bytes = EngineExtrasTrait::::pull_data(ref engine, n)?; +pub fn opcode_push_data_x< + T, + +Drop, + I, + +Drop, + impl IEngineTransactionInputTrait: EngineTransactionInputTrait, + O, + +Drop, + impl IEngineTransactionOutputTrait: EngineTransactionOutputTrait, + impl IEngineTransactionTrait: EngineTransactionTrait< + T, I, O, IEngineTransactionInputTrait, IEngineTransactionOutputTrait + > +>( + n: usize, ref engine: Engine +) -> Result<(), felt252> { + let data_len_bytes = EngineInternalTrait::::pull_data(ref engine, n)?; let data_len: usize = byte_array_to_felt252_le(@data_len_bytes).try_into().unwrap(); let data = engine.pull_data(data_len)?; engine.dstack.push_byte_array(data); diff --git a/packages/engine/src/opcodes/crypto.cairo b/packages/engine/src/opcodes/crypto.cairo index f7738eb7..c9761aac 100644 --- a/packages/engine/src/opcodes/crypto.cairo +++ b/packages/engine/src/opcodes/crypto.cairo @@ -1,64 +1,44 @@ -use crate::engine::{Engine, EngineExtrasTrait}; +use crate::engine::{Engine, EngineInternalImpl}; use crate::transaction::{ EngineTransactionTrait, EngineTransactionInputTrait, EngineTransactionOutputTrait }; use crate::stack::ScriptStackTrait; -use crate::scriptflags::ScriptFlags; +use crate::flags::ScriptFlags; use crate::signature::signature; use crate::signature::sighash; -use crate::signature::signature::BaseSigVerifierTrait; use starknet::secp256_trait::{is_valid_signature}; -use core::sha256::compute_sha256_byte_array; +use core::num::traits::OverflowingAdd; +use crate::signature::signature::{ + BaseSigVerifierTrait, BaseSegwitSigVerifierTrait, TaprootSigVerifierTrait +}; +use shinigami_utils::hash::{sha256_byte_array, double_sha256_bytearray}; use crate::opcodes::utils; use crate::scriptnum::ScriptNum; use crate::errors::Error; +use crate::taproot::TaprootContextTrait; const MAX_KEYS_PER_MULTISIG: i64 = 20; +const BASE_SEGWIT_VERSION: i64 = 0; pub fn opcode_sha256>(ref engine: Engine) -> Result<(), felt252> { let arr = @engine.dstack.pop_byte_array()?; - let res = compute_sha256_byte_array(arr).span(); - let mut res_bytes: ByteArray = ""; - let mut i: usize = 0; - while i != res.len() { - res_bytes.append_word((*res[i]).into(), 4); - i += 1; - }; - engine.dstack.push_byte_array(res_bytes); + let res = sha256_byte_array(arr); + engine.dstack.push_byte_array(res); return Result::Ok(()); } pub fn opcode_hash160>(ref engine: Engine) -> Result<(), felt252> { let m = engine.dstack.pop_byte_array()?; - let res = compute_sha256_byte_array(@m).span(); - let mut res_bytes: ByteArray = ""; - let mut i: usize = 0; - while i != res.len() { - res_bytes.append_word((*res[i]).into(), 4); - i += 1; - }; - let h: ByteArray = ripemd160::ripemd160_hash(@res_bytes).into(); + let res = sha256_byte_array(@m); + let h: ByteArray = ripemd160::ripemd160_hash(@res).into(); engine.dstack.push_byte_array(h); return Result::Ok(()); } pub fn opcode_hash256>(ref engine: Engine) -> Result<(), felt252> { let m = engine.dstack.pop_byte_array()?; - let res = compute_sha256_byte_array(@m).span(); - let mut res_bytes: ByteArray = ""; - let mut i: usize = 0; - while i != res.len() { - res_bytes.append_word((*res[i]).into(), 4); - i += 1; - }; - let res2 = compute_sha256_byte_array(@res_bytes).span(); - let mut res2_bytes: ByteArray = ""; - let mut j: usize = 0; - while j != res2.len() { - res2_bytes.append_word((*res2[j]).into(), 4); - j += 1; - }; - engine.dstack.push_byte_array(res2_bytes); + let res = double_sha256_bytearray(@m); + engine.dstack.push_byte_array(res.into()); return Result::Ok(()); } @@ -92,32 +72,66 @@ pub fn opcode_checksig< return Result::Ok(()); } - // TODO: add witness context inside engine to check if witness is active - // if witness is active use BaseSigVerifier let mut is_valid: bool = false; - let res = BaseSigVerifierTrait::new(ref engine, @full_sig_bytes, @pk_bytes); - if res.is_err() { - // TODO: Some errors can return an error code instead of pushing false? - engine.dstack.push_bool(false); - return Result::Ok(()); - } - let mut sig_verifier = res.unwrap(); + if engine.witness_program.len() == 0 { + // Base Signature Verification + let res = BaseSigVerifierTrait::new(ref engine, @full_sig_bytes, @pk_bytes); + if res.is_err() { + let err = res.unwrap_err(); + if err == Error::SCRIPT_ERR_SIG_DER || err == Error::WITNESS_PUBKEYTYPE { + return Result::Err(err); + }; + engine.dstack.push_bool(false); + return Result::Ok(()); + } - if sig_verifier.verify(ref engine) { - is_valid = true; - } else { - is_valid = false; - } - // else use BaseSigWitnessVerifier - // let mut sig_verifier: BaseSigWitnessVerifier = BaseSigWitnessVerifierTrait::new(ref engine, - // @full_sig_bytes, @pk_bytes)?; + let mut sig_verifier = res.unwrap(); + if BaseSigVerifierTrait::verify(ref sig_verifier, ref engine) { + is_valid = true; + } else { + is_valid = false; + } + } else if engine.is_witness_active(0) { + // Witness Signature Verification + let res = BaseSigVerifierTrait::new(ref engine, @full_sig_bytes, @pk_bytes); + if res.is_err() { + let err = res.unwrap_err(); + if err == Error::SCRIPT_ERR_SIG_DER || err == Error::WITNESS_PUBKEYTYPE { + return Result::Err(err); + }; + engine.dstack.push_bool(false); + return Result::Ok(()); + } - // if sig_verifier.verify(ref engine) { - // is_valid = true; - // } else { - // is_valid = false; - // } + let mut sig_verifier = res.unwrap(); + if BaseSegwitSigVerifierTrait::verify(ref sig_verifier, ref engine) { + is_valid = true; + } else { + is_valid = false; + } + } else if engine.use_taproot { + // Taproot Signature Verification + engine.taproot_context.use_ops_budget()?; + if pk_bytes.len() == 0 { + return Result::Err(Error::TAPROOT_EMPTY_PUBKEY); + } + let mut verifier = TaprootSigVerifierTrait::< + I, O, T + >::new(@full_sig_bytes, @pk_bytes, engine.taproot_context.annex)?; + if !(TaprootSigVerifierTrait::::verify(ref verifier)) { + return Result::Err(Error::TAPROOT_INVALID_SIG); + } + + let mut verifier = TaprootSigVerifierTrait::< + I, O, T + >::new_base(@full_sig_bytes, @pk_bytes)?; + is_valid = TaprootSigVerifierTrait::::verify(ref verifier); + } + + if !is_valid && @engine.use_taproot == @true { + return Result::Err(Error::SIG_NULLFAIL); + } if !is_valid && engine.has_flag(ScriptFlags::ScriptVerifyNullFail) && full_sig_bytes.len() > 0 { return Result::Err(Error::SIG_NULLFAIL); } @@ -141,8 +155,11 @@ pub fn opcode_checkmultisig< >( ref engine: Engine ) -> Result<(), felt252> { - // TODO Error on taproot exec + if engine.use_taproot { + return Result::Err(Error::TAPROOT_MULTISIG); + } + let verify_der = engine.has_flag(ScriptFlags::ScriptVerifyDERSignatures); // Get number of public keys and construct array let num_keys = engine.dstack.pop_int()?; let mut num_pub_keys: i64 = ScriptNum::to_int32(num_keys).into(); @@ -202,10 +219,10 @@ pub fn opcode_checkmultisig< let mut script = engine.sub_script(); - // TODO: add witness context inside engine to check if witness is active let mut s: u32 = 0; - while s != sigs.len() { - script = signature::remove_signature(script, sigs.at(s)); + let end = sigs.len(); + while s != end { + script = signature::remove_signature(@script, sigs.at(s)).clone(); s += 1; }; @@ -227,36 +244,42 @@ pub fn opcode_checkmultisig< if sig.len() == 0 { continue; } - let res = signature::parse_base_sig_and_pk(ref engine, pub_key, sig); if res.is_err() { success = false; err = res.unwrap_err(); break; } + let (parsed_pub_key, parsed_sig, hash_type) = res.unwrap(); let sig_hash: u256 = sighash::calc_signature_hash( - @script, hash_type, ref engine.transaction, engine.tx_idx + @script, hash_type, engine.transaction, engine.tx_idx ); + if is_valid_signature(sig_hash, parsed_sig.r, parsed_sig.s, parsed_pub_key) { sig_idx += 1; num_sigs -= 1; } }; + if err != 0 { return Result::Err(err); } - if !success && engine.has_flag(ScriptFlags::ScriptVerifyNullFail) { - let mut err = ''; - for s in sigs { - if s.len() > 0 { - err = Error::SIG_NULLFAIL; - break; + if !success { + if engine.has_flag(ScriptFlags::ScriptVerifyNullFail) { + let mut err = ''; + for s in sigs { + if s.len() > 0 { + err = Error::SIG_NULLFAIL; + break; + } + }; + if err != '' { + return Result::Err(err); } - }; - if err != '' { - return Result::Err(err); + } else if verify_der { + return Result::Err(Error::SCRIPT_ERR_SIG_DER); } } @@ -264,15 +287,30 @@ pub fn opcode_checkmultisig< Result::Ok(()) } -pub fn opcode_codeseparator>(ref engine: Engine) -> Result<(), felt252> { +pub fn opcode_codeseparator< + T, + +Drop, + I, + +Drop, + impl IEngineTransactionInputTrait: EngineTransactionInputTrait, + O, + +Drop, + impl IEngineTransactionOutputTrait: EngineTransactionOutputTrait, + impl IEngineTransactionTrait: EngineTransactionTrait< + T, I, O, IEngineTransactionInputTrait, IEngineTransactionOutputTrait + > +>( + ref engine: Engine +) -> Result<(), felt252> { engine.last_code_sep = engine.opcode_idx; - // TODO Disable OP_CODESEPARATOR for non-segwit scripts. - // if engine.witness_program.len() == 0 && - // engine.has_flag(ScriptFlags::ScriptVerifyConstScriptCode) { - - // return Result::Err('opcode_codeseparator:non-segwit'); - // } + if !engine.use_taproot { + // TODO: Check if this is correct + engine.taproot_context.code_sep = engine.opcode_idx; + } else if engine.witness_program.len() == 0 + && engine.has_flag(ScriptFlags::ScriptVerifyConstScriptCode) { + return Result::Err(Error::CODESEPARATOR_NON_SEGWIT); + } Result::Ok(()) } @@ -323,3 +361,79 @@ pub fn opcode_sha1>(ref engine: Engine) -> Result<(), felt252> { engine.dstack.push_byte_array(h); return Result::Ok(()); } + +// https://github.com/btcsuite/btcd/blob/67b8efd3ba53b60ff0eba5d79babe2c3d82f6c54/txscript/opcode.go#L2126 +// opcodeCheckSigAdd implements the OP_CHECKSIGADD operation defined in BIP +// 342. This is a replacement for OP_CHECKMULTISIGVERIFY and OP_CHECKMULTISIG +// that lends better to batch sig validation, as well as a possible future of +// signature aggregation across inputs. +// +// The op code takes a public key, an integer (N) and a signature, and returns +// N if the signature was the empty vector, and n+1 otherwise. +// +// Stack transformation: [... pubkey n signature] -> [... n | n+1 ] -> [...] +pub fn opcode_checksigadd< + T, + +Drop, + I, + +Drop, + impl IEngineTransactionInputTrait: EngineTransactionInputTrait, + O, + +Drop, + impl IEngineTransactionOutputTrait: EngineTransactionOutputTrait, + impl IEngineTransactionTrait: EngineTransactionTrait< + T, I, O, IEngineTransactionInputTrait, IEngineTransactionOutputTrait + > +>( + ref engine: Engine +) -> Result<(), felt252> { + // This op code can only be used if tapscript execution is active. + // Before the soft fork, this opcode was marked as an invalid reserved + // op code. + if !engine.use_taproot { + return Result::Err(Error::OPCODE_RESERVED); + } + + let pk_bytes: ByteArray = engine.dstack.pop_byte_array()?; + let n: i64 = engine.dstack.pop_int()?; + let sig_bytes: ByteArray = engine.dstack.pop_byte_array()?; + + // Only non-empty signatures count towards the total tapscript sig op + // limit. + if sig_bytes.len() != 0 { + // Account for changes in the sig ops budget after this execution. + engine.taproot_context.use_ops_budget()?; + } + + // Empty public keys immediately cause execution to fail. + if pk_bytes.len() == 0 { + return Result::Err(Error::TAPROOT_EMPTY_PUBKEY); + } + + // If the signature is empty, then we'll just push the value N back + // onto the stack and continue from here. + if sig_bytes.len() == 0 { + engine.dstack.push_int(n); + return Result::Ok(()); + } + + // Otherwise, we'll attempt to validate the signature as normal. + // + // If the constructor fails immediately, then it's because the public + // key size is zero, so we'll fail all script execution. + let mut verifier = TaprootSigVerifierTrait::< + I, O, T + >::new(@sig_bytes, @pk_bytes, engine.taproot_context.annex)?; + if !(TaprootSigVerifierTrait::::verify(ref verifier)) { + return Result::Err(Error::TAPROOT_INVALID_SIG); + } + + // Otherwise, we increment the accumulatorInt by one, and push that + // back onto the stack. + let (n_add_1, overflow) = n.overflowing_add(1); + if overflow { + return Result::Err(Error::STACK_OVERFLOW); + } + engine.dstack.push_int(n_add_1); + Result::Ok(()) +} diff --git a/packages/engine/src/opcodes/flow.cairo b/packages/engine/src/opcodes/flow.cairo index 56ec7e25..efe97979 100644 --- a/packages/engine/src/opcodes/flow.cairo +++ b/packages/engine/src/opcodes/flow.cairo @@ -1,23 +1,30 @@ -use crate::engine::{Engine, EngineExtrasTrait}; +use crate::engine::{Engine, EngineInternalTrait}; +use crate::transaction::{ + EngineTransactionTrait, EngineTransactionInputTrait, EngineTransactionOutputTrait +}; +use crate::flags::ScriptFlags; use crate::cond_stack::ConditionalStackTrait; use crate::opcodes::{utils, Opcode}; -use crate::scriptflags::ScriptFlags; use crate::errors::Error; -pub fn is_branching_opcode(opcode: u8) -> bool { - if opcode == Opcode::OP_IF - || opcode == Opcode::OP_NOTIF - || opcode == Opcode::OP_ELSE - || opcode == Opcode::OP_ENDIF { - return true; - } - return false; -} - -pub fn opcode_nop>(ref engine: Engine, opcode: u8) -> Result<(), felt252> { +pub fn opcode_nop< + T, + +Drop, + I, + +Drop, + impl IEngineTransactionInputTrait: EngineTransactionInputTrait, + O, + +Drop, + impl IEngineTransactionOutputTrait: EngineTransactionOutputTrait, + impl IEngineTransactionTrait: EngineTransactionTrait< + T, I, O, IEngineTransactionInputTrait, IEngineTransactionOutputTrait + > +>( + ref engine: Engine, opcode: u8 +) -> Result<(), felt252> { if opcode != Opcode::OP_NOP - && EngineExtrasTrait::< - T + && EngineInternalTrait::< + I, O, T >::has_flag(ref engine, ScriptFlags::ScriptDiscourageUpgradableNops) { return Result::Err(Error::SCRIPT_DISCOURAGE_UPGRADABLE_NOPS); } @@ -28,7 +35,21 @@ pub fn opcode_nop>(ref engine: Engine, opcode: u8) -> Result<(), const op_cond_false: u8 = 0; const op_cond_true: u8 = 1; const op_cond_skip: u8 = 2; -pub fn opcode_if>(ref engine: Engine) -> Result<(), felt252> { +pub fn opcode_if< + T, + +Drop, + I, + +Drop, + impl IEngineTransactionInputTrait: EngineTransactionInputTrait, + O, + +Drop, + impl IEngineTransactionOutputTrait: EngineTransactionOutputTrait, + impl IEngineTransactionTrait: EngineTransactionTrait< + T, I, O, IEngineTransactionInputTrait, IEngineTransactionOutputTrait + > +>( + ref engine: Engine +) -> Result<(), felt252> { let mut cond = op_cond_false; // TODO: Pop if bool if engine.cond_stack.branch_executing() { @@ -43,7 +64,21 @@ pub fn opcode_if>(ref engine: Engine) -> Result<(), felt252> { return Result::Ok(()); } -pub fn opcode_notif>(ref engine: Engine) -> Result<(), felt252> { +pub fn opcode_notif< + T, + +Drop, + I, + +Drop, + impl IEngineTransactionInputTrait: EngineTransactionInputTrait, + O, + +Drop, + impl IEngineTransactionOutputTrait: EngineTransactionOutputTrait, + impl IEngineTransactionTrait: EngineTransactionTrait< + T, I, O, IEngineTransactionInputTrait, IEngineTransactionOutputTrait + > +>( + ref engine: Engine +) -> Result<(), felt252> { let mut cond = op_cond_false; if engine.cond_stack.branch_executing() { let ok = engine.pop_if_bool()?; diff --git a/packages/engine/src/opcodes/locktime.cairo b/packages/engine/src/opcodes/locktime.cairo index 7dbd114f..4cd068c6 100644 --- a/packages/engine/src/opcodes/locktime.cairo +++ b/packages/engine/src/opcodes/locktime.cairo @@ -1,9 +1,9 @@ -use crate::engine::{Engine, EngineExtrasTrait}; +use crate::engine::{Engine, EngineInternalImpl}; use crate::transaction::{ EngineTransactionTrait, EngineTransactionInputTrait, EngineTransactionOutputTrait }; use crate::errors::Error; -use crate::scriptflags::ScriptFlags; +use crate::flags::ScriptFlags; use crate::scriptnum::ScriptNum; use crate::stack::ScriptStackTrait; @@ -53,7 +53,7 @@ pub fn opcode_checklocktimeverify< let tx_locktime: i64 = EngineTransactionTrait::< T, I, O, IEngineTransactionInputTrait, IEngineTransactionOutputTrait - >::get_locktime(@engine.transaction) + >::get_locktime(engine.transaction) .into(); // Get locktime as 5 byte integer because 'tx_locktime' is u32 let stack_locktime: i64 = ScriptNum::try_into_num_n_bytes( @@ -68,7 +68,7 @@ pub fn opcode_checklocktimeverify< // behavior of OP_CHECKLOCKTIMEVERIFY can be bypassed let transaction_input = EngineTransactionTrait::< T, I, O, IEngineTransactionInputTrait, IEngineTransactionOutputTrait - >::get_transaction_inputs(@engine.transaction) + >::get_transaction_inputs(engine.transaction) .at(engine.tx_idx); let sequence = EngineTransactionInputTrait::::get_sequence(transaction_input); if sequence == SEQUENCE_MAX { @@ -121,14 +121,14 @@ pub fn opcode_checksequenceverify< // Prevent trigger OP_CHECKSEQUENCEVERIFY before tx version 2 let version = EngineTransactionTrait::< T, I, O, IEngineTransactionInputTrait, IEngineTransactionOutputTrait - >::get_version(@engine.transaction); + >::get_version(engine.transaction); if version < 2 { return Result::Err(Error::INVALID_TX_VERSION); } let transaction_input = EngineTransactionTrait::< T, I, O, IEngineTransactionInputTrait, IEngineTransactionOutputTrait - >::get_transaction_inputs(@engine.transaction) + >::get_transaction_inputs(engine.transaction) .at(engine.tx_idx); let tx_sequence: u32 = EngineTransactionInputTrait::::get_sequence(transaction_input); diff --git a/packages/engine/src/opcodes/opcodes.cairo b/packages/engine/src/opcodes/opcodes.cairo index 8b1a56ab..8253a2a3 100644 --- a/packages/engine/src/opcodes/opcodes.cairo +++ b/packages/engine/src/opcodes/opcodes.cairo @@ -1,7 +1,6 @@ -use shinigami_utils::byte_array::byte_array_to_felt252_le; - pub mod Opcode { pub const OP_0: u8 = 0; + pub const OP_FALSE: u8 = 0; pub const OP_DATA_1: u8 = 1; pub const OP_DATA_2: u8 = 2; pub const OP_DATA_3: u8 = 3; @@ -179,7 +178,9 @@ pub mod Opcode { pub const OP_CHECKMULTISIG: u8 = 174; pub const OP_CHECKMULTISIGVERIFY: u8 = 175; pub const OP_NOP1: u8 = 176; + pub const OP_NOP2: u8 = 177; pub const OP_CHECKLOCKTIMEVERIFY: u8 = 177; + pub const OP_NOP3: u8 = 178; pub const OP_CHECKSEQUENCEVERIFY: u8 = 178; pub const OP_NOP4: u8 = 179; pub const OP_NOP5: u8 = 180; @@ -196,6 +197,7 @@ pub mod Opcode { use crate::opcodes::{ constants, flow, stack, splice, bitwise, arithmetic, crypto, locktime, utils }; + use crate::parser::data_len; pub fn execute< T, @@ -470,41 +472,56 @@ pub mod Opcode { return true; } - use crate::errors::Error; - pub fn data_at(idx: usize, len: usize, script: @ByteArray) -> Result { - let mut data = ""; - let mut i = idx; - let mut end = i + len; - if end > script.len() { - return Result::Err(Error::SCRIPT_INVALID); + pub fn is_branching_opcode(opcode: u8) -> bool { + if opcode == OP_IF || opcode == OP_NOTIF || opcode == OP_ELSE || opcode == OP_ENDIF { + return true; } - while i != end { - data.append_byte(script[i]); - i += 1; - }; - return Result::Ok(data); + return false; } - pub fn data_len(idx: u32, script: @ByteArray) -> Result { - let opcode: u8 = script[idx]; - if is_data_opcode(opcode) { - return Result::Ok(opcode.into()); + pub fn is_success_opcode(opcode: u8) -> bool { + // TODO: To map + if opcode > 186 { + // OP_UNKNOWNX + return true; } - let mut push_data_len = 0; - if opcode == OP_PUSHDATA1 { - push_data_len = 1; - } else if opcode == OP_PUSHDATA2 { - push_data_len = 2; - } else if opcode == OP_PUSHDATA4 { - push_data_len = 4; - } else { - return Result::Ok(0); + if opcode == OP_RESERVED + || opcode == OP_VER + || 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_RESERVED1 + || opcode == OP_RESERVED2 + || opcode == OP_2MUL + || opcode == OP_2DIV + || opcode == OP_MUL + || opcode == OP_DIV + || opcode == OP_MOD + || opcode == OP_LSHIFT + || opcode == OP_RSHIFT { + return true; } - return Result::Ok( - super::byte_array_to_felt252_le(@data_at(idx + 1, push_data_len, script)?) - .try_into() - .unwrap() - + push_data_len - ); + return false; + } + + pub fn has_success_opcode(script: @ByteArray) -> bool { + let mut i: usize = 0; + let mut result = false; + + while i < script.len() { + let opcode = script[i]; + if is_success_opcode(opcode) { + result = true; + break; + } + let data_len = data_len(script, i).unwrap(); + i += data_len + 1; + }; + return result; } } diff --git a/packages/engine/src/opcodes/utils.cairo b/packages/engine/src/opcodes/utils.cairo index 5221af46..1541114f 100644 --- a/packages/engine/src/opcodes/utils.cairo +++ b/packages/engine/src/opcodes/utils.cairo @@ -11,7 +11,7 @@ pub fn abstract_verify>(ref engine: Engine) -> Result<(), felt252 } pub fn not_implemented(ref engine: Engine) -> Result<(), felt252> { - return Result::Err(Error::OPCODE_NOT_IMPLEMENTED); + return Result::Err(Error::OPCODE_RESERVED); } pub fn opcode_reserved(msg: ByteArray, ref engine: Engine) -> Result<(), felt252> { diff --git a/packages/engine/src/parser.cairo b/packages/engine/src/parser.cairo new file mode 100644 index 00000000..b3b14ccb --- /dev/null +++ b/packages/engine/src/parser.cairo @@ -0,0 +1,96 @@ +use shinigami_utils::byte_array::byte_array_to_felt252_le; +use crate::opcodes::{opcodes::Opcode}; +use crate::errors::Error; + +// Returns true if the script is a script hash +pub fn is_script_hash(script_pubkey: @ByteArray) -> bool { + if script_pubkey.len() == 23 + && script_pubkey[0] == Opcode::OP_HASH160 + && script_pubkey[1] == Opcode::OP_DATA_20 + && script_pubkey[22] == Opcode::OP_EQUAL { + return true; + } + return false; +} + + +// Returns true if the script sig is push only +pub fn is_push_only(script: @ByteArray) -> bool { + let mut i = 0; + let mut is_push_only = true; + let script_len = script.len(); + while i != script_len { + // TODO: Error handling if i outside bounds + let opcode = script[i]; + if opcode > Opcode::OP_16 { + is_push_only = false; + break; + } + + // TODO: Error handling + let data_len = data_len(script, i).unwrap(); + i += data_len + 1; + }; + return is_push_only; +} + +// Returns the data in the script at the given index +pub fn data_at(script: @ByteArray, mut idx: usize, len: usize) -> Result { + let mut data = ""; + let mut end = idx + len; + if end > script.len() { + return Result::Err(Error::SCRIPT_INVALID); + } + while idx != end { + data.append_byte(script[idx]); + idx += 1; + }; + return Result::Ok(data); +} + +// Returns the length of all the data associated with the opcode at the given index +pub fn data_len(script: @ByteArray, idx: usize) -> Result { + let opcode: u8 = script[idx]; + if Opcode::is_data_opcode(opcode) { + return Result::Ok(opcode.into()); + } + let mut push_data_len = 0; + if opcode == Opcode::OP_PUSHDATA1 { + push_data_len = 1; + } else if opcode == Opcode::OP_PUSHDATA2 { + push_data_len = 2; + } else if opcode == Opcode::OP_PUSHDATA4 { + push_data_len = 4; + } else { + return Result::Ok(0); + } + return Result::Ok( + byte_array_to_felt252_le(@data_at(script, idx + 1, push_data_len)?).try_into().unwrap() + + push_data_len + ); +} + +// Returns the length of the data associated with the push data opcode at the given index +pub fn push_data_len(script: @ByteArray, idx: usize) -> Result { + let mut len = 0; + let opcode: u8 = script[idx]; + if opcode == Opcode::OP_PUSHDATA1 { + len = 1; + } else if opcode == Opcode::OP_PUSHDATA2 { + len = 2; + } else if opcode == Opcode::OP_PUSHDATA4 { + len = 4; + } else { + return Result::Err(Error::SCRIPT_INVALID); + } + + return Result::Ok( + byte_array_to_felt252_le(@data_at(script, idx + 1, len)?).try_into().unwrap() + ); +} + +// Return the next opcode_idx in the script +pub fn next(script: @ByteArray, idx: usize) -> Result { + let data_len = data_len(script, idx)?; + return Result::Ok(idx + data_len + 1); +} diff --git a/packages/engine/src/scriptnum.cairo b/packages/engine/src/scriptnum.cairo index 89407eb7..05b9559f 100644 --- a/packages/engine/src/scriptnum.cairo +++ b/packages/engine/src/scriptnum.cairo @@ -77,7 +77,8 @@ pub mod ScriptNum { return Result::Ok(0); } let snap_input = @input; - while i != snap_input.len() - 1 { + let end = snap_input.len() - 1; + while i != end { result += snap_input.at(i).unwrap().into() * multiplier; multiplier *= BYTESHIFT; i += 1; @@ -117,7 +118,8 @@ pub mod ScriptNum { return Result::Ok(0); } let snap_input = @input; - while i != snap_input.len() - 1 { + let end = snap_input.len() - 1; + while i != end { result += snap_input.at(i).unwrap().into() * multiplier; multiplier *= BYTESHIFT; i += 1; diff --git a/packages/engine/src/signature/sighash.cairo b/packages/engine/src/signature/sighash.cairo index bc163570..923f4e7d 100644 --- a/packages/engine/src/signature/sighash.cairo +++ b/packages/engine/src/signature/sighash.cairo @@ -1,29 +1,31 @@ use crate::transaction::{ - Transaction, TransactionTrait, TransactionInput, TransactionOutput, EngineTransactionTrait, + EngineTransaction, EngineTransactionTrait, EngineInternalTransactionImpl, EngineTransactionInputTrait, EngineTransactionOutputTrait }; use crate::signature::constants; use crate::signature::utils::{ remove_opcodeseparator, transaction_procedure, is_witness_pub_key_hash }; +use crate::hash_cache::SegwitSigHashMidstate; use shinigami_utils::bytecode::int_size_in_bytes; use shinigami_utils::hash::double_sha256; +use crate::opcodes::opcodes::Opcode; // Calculates the signature hash for specified transaction data and hash type. pub fn calc_signature_hash< - T, - +Drop, I, - +Drop, - impl IEngineTransactionInputTrait: EngineTransactionInputTrait, O, + T, + impl IEngineTransactionInput: EngineTransactionInputTrait, + impl IEngineTransactionOutput: EngineTransactionOutputTrait, + impl IEngineTransaction: EngineTransactionTrait< + T, I, O, IEngineTransactionInput, IEngineTransactionOutput + >, + +Drop, +Drop, - impl IEngineTransactionOutputTrait: EngineTransactionOutputTrait, - impl IEngineTransactionTrait: EngineTransactionTrait< - T, I, O, IEngineTransactionInputTrait, IEngineTransactionOutputTrait - > + +Drop >( - sub_script: @ByteArray, hash_type: u32, ref transaction: T, tx_idx: u32 + sub_script: @ByteArray, hash_type: u32, transaction: @T, tx_idx: u32 ) -> u256 { let transaction_outputs_len: usize = transaction.get_transaction_outputs().len(); // `SIG_HASH_SINGLE` only signs corresponding input/output pair. @@ -38,8 +40,8 @@ pub fn calc_signature_hash< // Remove any OP_CODESEPARATOR opcodes from the subscript. let mut signature_script: @ByteArray = remove_opcodeseparator(sub_script); // Create a modified copy of the transaction according to the hash type. - let transaction_copy: Transaction = transaction_procedure( - ref transaction, tx_idx, signature_script.clone(), hash_type + let transaction_copy: EngineTransaction = transaction_procedure( + transaction, tx_idx, signature_script.clone(), hash_type ); let mut sig_hash_bytes: ByteArray = transaction_copy.serialize_no_witness(); @@ -50,126 +52,108 @@ pub fn calc_signature_hash< } // Calculates the signature hash for a Segregated Witness (SegWit) transaction and hash type. -pub fn calc_witness_transaction_hash( - sub_script: @ByteArray, hash_type: u32, ref transaction: Transaction, index: u32, amount: i64 +pub fn calc_witness_signature_hash< + I, + O, + T, + impl IEngineTransactionInput: EngineTransactionInputTrait, + impl IEngineTransactionOutput: EngineTransactionOutputTrait, + impl IEngineTransaction: EngineTransactionTrait< + T, I, O, IEngineTransactionInput, IEngineTransactionOutput + >, + +Drop, + +Drop, + +Drop +>( + sub_script: @ByteArray, + sig_hashes: @SegwitSigHashMidstate, + hash_type: u32, + transaction: @T, + tx_idx: u32, + amount: i64 ) -> u256 { - let transaction_outputs_len: usize = transaction.transaction_outputs.len(); - if hash_type & constants::SIG_HASH_MASK == constants::SIG_HASH_SINGLE - && index > transaction_outputs_len { - return 0x01; - } - let mut sig_hash_bytes: ByteArray = ""; - let mut input_byte: ByteArray = ""; - let mut output_byte: ByteArray = ""; - let mut sequence_byte: ByteArray = ""; - // Serialize the transaction's version number. - sig_hash_bytes.append_word_rev(transaction.version.into(), 4); - // Serialize each input in the transaction. - let input_len: usize = transaction.transaction_inputs.len(); - let mut i: usize = 0; - while i != input_len { - let input: @TransactionInput = transaction.transaction_inputs.at(i); - - let input_txid: u256 = *input.previous_outpoint.txid; - let vout: u32 = *input.previous_outpoint.vout; - let sequence: u32 = *input.sequence; - - input_byte.append_word(input_txid.high.into(), 16); - input_byte.append_word(input_txid.low.into(), 16); - input_byte.append_word_rev(vout.into(), 4); - sequence_byte.append_word_rev(sequence.into(), 4); - - i += 1; - }; - // Serialize each output if not using SIG_HASH_SINGLE or SIG_HASH_NONE else serialize only the - // relevant output. - if hash_type & constants::SIG_HASH_SINGLE != constants::SIG_HASH_SINGLE - && hash_type & constants::SIG_HASH_NONE != constants::SIG_HASH_NONE { - let output_len: usize = transaction.transaction_outputs.len(); + // TODO: Bounds check? - i = 0; - while i != output_len { - let output: @TransactionOutput = transaction.transaction_outputs.at(i); - let value: i64 = *output.value; - let script: @ByteArray = output.publickey_script; - let script_len: usize = script.len(); - - output_byte.append_word_rev(value.into(), 8); - output_byte.append_word_rev(script_len.into(), int_size_in_bytes(script_len)); - output_byte.append(script); - - i += 1; - }; - } else if hash_type & constants::SIG_HASH_SINGLE == constants::SIG_HASH_SINGLE { - if index < transaction.transaction_outputs.len() { - let output: @TransactionOutput = transaction.transaction_outputs.at(index); - let value: i64 = *output.value; - let script: @ByteArray = output.publickey_script; - let script_len: usize = script.len(); - - output_byte.append_word_rev(value.into(), 8); - output_byte.append_word_rev(script_len.into(), int_size_in_bytes(script_len)); - output_byte.append(script); - } - } - let mut hash_prevouts: u256 = 0; - if hash_type & constants::SIG_HASH_ANYONECANPAY != constants::SIG_HASH_ANYONECANPAY { - hash_prevouts = double_sha256(@input_byte); - } + let mut sig_hash_bytes: ByteArray = ""; + sig_hash_bytes.append_word_rev(transaction.get_version().into(), 4); - let mut hash_sequence: u256 = 0; - if hash_type & constants::SIG_HASH_ANYONECANPAY != constants::SIG_HASH_ANYONECANPAY - && hash_type & constants::SIG_HASH_SINGLE != constants::SIG_HASH_SINGLE - && hash_type & constants::SIG_HASH_NONE != constants::SIG_HASH_NONE { - hash_sequence = double_sha256(@sequence_byte); + let zero: u256 = 0; + if hash_type & constants::SIG_HASH_ANYONECANPAY == 0 { + let hash_prevouts_v0: u256 = *sig_hashes.hash_prevouts_v0; + sig_hash_bytes.append_word(hash_prevouts_v0.high.into(), 16); + sig_hash_bytes.append_word(hash_prevouts_v0.low.into(), 16); + } else { + sig_hash_bytes.append_word(zero.high.into(), 16); + sig_hash_bytes.append_word(zero.low.into(), 16); } - let mut hash_outputs: u256 = 0; - if hash_type & constants::SIG_HASH_ANYONECANPAY == constants::SIG_HASH_ANYONECANPAY - || hash_type & constants::SIG_HASH_SINGLE == constants::SIG_HASH_SINGLE - || hash_type & constants::SIG_HASH_ALL == constants::SIG_HASH_ALL { - hash_sequence = double_sha256(@output_byte); + if hash_type & constants::SIG_HASH_ANYONECANPAY == 0 + && hash_type & constants::SIG_HASH_MASK != constants::SIG_HASH_SINGLE + && hash_type & constants::SIG_HASH_MASK != constants::SIG_HASH_NONE { + let hash_sequence_v0: u256 = *sig_hashes.hash_sequence_v0; + sig_hash_bytes.append_word(hash_sequence_v0.high.into(), 16); + sig_hash_bytes.append_word(hash_sequence_v0.low.into(), 16); + } else { + sig_hash_bytes.append_word(zero.high.into(), 16); + sig_hash_bytes.append_word(zero.low.into(), 16); } - // Append the hashed previous outputs and sequences. - sig_hash_bytes.append_word_rev(hash_prevouts.high.into(), 16); - sig_hash_bytes.append_word_rev(hash_prevouts.low.into(), 16); - sig_hash_bytes.append_word_rev(hash_sequence.high.into(), 16); - sig_hash_bytes.append_word_rev(hash_sequence.low.into(), 16); - // Add the input being signed. + let input = transaction.get_transaction_inputs().at(tx_idx); + sig_hash_bytes.append_word(input.get_prevout_txid().high.into(), 16); + sig_hash_bytes.append_word(input.get_prevout_txid().low.into(), 16); + sig_hash_bytes.append_word_rev(input.get_prevout_vout().into(), 4); - let mut input: @TransactionInput = transaction.transaction_inputs.at(i); - let input_txid: u256 = *input.previous_outpoint.txid; - let vout: u32 = *input.previous_outpoint.vout; - let sequence: u32 = *input.sequence; - sig_hash_bytes.append_word_rev(input_txid.high.into(), 16); - sig_hash_bytes.append_word_rev(input_txid.low.into(), 16); - sig_hash_bytes.append_word_rev(vout.into(), 4); - // Check if the script is a witness pubkey hash and serialize accordingly. if is_witness_pub_key_hash(sub_script) { + // P2WKH with 0x19 OP_DUP OP_HASH160 OP_DATA_20 OP_EQUALVERIFY OP_CHECKSIG sig_hash_bytes.append_byte(0x19); - sig_hash_bytes.append_byte(0x76); - sig_hash_bytes.append_byte(0xa9); - sig_hash_bytes.append_byte(0x14); - i = 2; - while i != sub_script.len() { + sig_hash_bytes.append_byte(Opcode::OP_DUP); + sig_hash_bytes.append_byte(Opcode::OP_HASH160); + sig_hash_bytes.append_byte(Opcode::OP_DATA_20); + let subscript_len = sub_script.len(); + // TODO: extractWitnessPubKeyHash + let mut i: usize = 2; + while i != subscript_len { sig_hash_bytes.append_byte(sub_script[i]); i += 1; }; - sig_hash_bytes.append_byte(0x88); - sig_hash_bytes.append_byte(0xac); + sig_hash_bytes.append_byte(Opcode::OP_EQUALVERIFY); + sig_hash_bytes.append_byte(Opcode::OP_CHECKSIG); } else { + // TODO: VarIntBuf + sig_hash_bytes + .append_word_rev(sub_script.len().into(), int_size_in_bytes(sub_script.len())); sig_hash_bytes.append(sub_script); } - // Serialize the amount and sequence number. + sig_hash_bytes.append_word_rev(amount.into(), 8); - sig_hash_bytes.append_word_rev(sequence.into(), 4); - // Serialize the hashed outputs. - sig_hash_bytes.append_word_rev(hash_outputs.high.into(), 16); - sig_hash_bytes.append_word_rev(hash_outputs.low.into(), 16); - // Serialize the transaction's locktime and hash type. - sig_hash_bytes.append_word_rev(transaction.locktime.into(), 4); + sig_hash_bytes.append_word_rev(input.get_sequence().into(), 4); + + if hash_type & constants::SIG_HASH_MASK != constants::SIG_HASH_SINGLE + && hash_type & constants::SIG_HASH_MASK != constants::SIG_HASH_NONE { + let hash_outputs_v0: u256 = *sig_hashes.hash_outputs_v0; + sig_hash_bytes.append_word(hash_outputs_v0.high.into(), 16); + sig_hash_bytes.append_word(hash_outputs_v0.low.into(), 16); + } else if hash_type & constants::SIG_HASH_MASK == constants::SIG_HASH_SINGLE + && tx_idx < transaction.get_transaction_outputs().len() { + let output = transaction.get_transaction_outputs().at(tx_idx); + let mut output_bytes: ByteArray = ""; + output_bytes.append_word_rev(output.get_value().into(), 8); + output_bytes + .append_word_rev( + output.get_publickey_script().len().into(), + int_size_in_bytes(output.get_publickey_script().len()) + ); + output_bytes.append(output.get_publickey_script()); + let hashed_output: u256 = double_sha256(@output_bytes); + sig_hash_bytes.append_word(hashed_output.high.into(), 16); + sig_hash_bytes.append_word(hashed_output.low.into(), 16); + } else { + sig_hash_bytes.append_word(zero.high.into(), 16); + sig_hash_bytes.append_word(zero.low.into(), 16); + } + + sig_hash_bytes.append_word_rev(transaction.get_locktime().into(), 4); sig_hash_bytes.append_word_rev(hash_type.into(), 4); - // Hash and return the serialized transaction data twice using SHA-256. + double_sha256(@sig_hash_bytes) } diff --git a/packages/engine/src/signature/signature.cairo b/packages/engine/src/signature/signature.cairo index 4c26f30b..69437ebe 100644 --- a/packages/engine/src/signature/signature.cairo +++ b/packages/engine/src/signature/signature.cairo @@ -1,13 +1,15 @@ -use crate::engine::{Engine, EngineExtrasTrait}; +use crate::engine::{Engine, EngineInternalImpl}; use crate::transaction::{ - EngineTransactionTrait, EngineTransactionInputTrait, EngineTransactionOutputTrait + EngineTransactionInputTrait, EngineTransactionOutputTrait, EngineTransactionTrait }; use starknet::SyscallResultTrait; use starknet::secp256_trait::{Secp256Trait, Signature, is_valid_signature}; use starknet::secp256k1::{Secp256k1Point}; -use crate::scriptflags::ScriptFlags; +use crate::flags::ScriptFlags; +use crate::hash_cache::SigHashMidstateTrait; use shinigami_utils::byte_array::u256_from_byte_array_with_offset; use crate::signature::{sighash, constants}; +use crate::errors::Error; //`BaseSigVerifier` is used to verify ECDSA signatures encoded in DER or BER format (pre-SegWit sig) #[derive(Drop)] @@ -26,7 +28,14 @@ pub struct BaseSigVerifier { hash_type: u32, } -pub trait BaseSigVerifierTrait { +pub trait BaseSigVerifierTrait< + I, + O, + T, + +EngineTransactionInputTrait, + +EngineTransactionOutputTrait, + +EngineTransactionTrait +> { fn new( ref vm: Engine, sig_bytes: @ByteArray, pk_bytes: @ByteArray ) -> Result; @@ -34,32 +43,66 @@ pub trait BaseSigVerifierTrait { } impl BaseSigVerifierImpl< - T, - +Drop, I, - +Drop, - impl IEngineTransactionInputTrait: EngineTransactionInputTrait, O, + T, + impl IEngineTransactionInput: EngineTransactionInputTrait, + impl IEngineTransactionOutput: EngineTransactionOutputTrait, + impl IEngineTransaction: EngineTransactionTrait< + T, I, O, IEngineTransactionInput, IEngineTransactionOutput + >, + +Drop, +Drop, - impl IEngineTransactionOutputTrait: EngineTransactionOutputTrait, - impl IEngineTransactionTrait: EngineTransactionTrait< - T, I, O, IEngineTransactionInputTrait, IEngineTransactionOutputTrait - > -> of BaseSigVerifierTrait { + +Drop +> of BaseSigVerifierTrait { fn new( ref vm: Engine, sig_bytes: @ByteArray, pk_bytes: @ByteArray ) -> Result { - let mut sub_script = vm.sub_script(); - sub_script = remove_signature(sub_script, sig_bytes); let (pub_key, sig, hash_type) = parse_base_sig_and_pk(ref vm, pk_bytes, sig_bytes)?; + let sub_script = vm.sub_script(); Result::Ok(BaseSigVerifier { pub_key, sig, sig_bytes, pk_bytes, sub_script, hash_type }) } // TODO: add signature cache mechanism for optimization fn verify(ref self: BaseSigVerifier, ref vm: Engine) -> bool { - let sig_hash: u256 = sighash::calc_signature_hash( - @self.sub_script, self.hash_type, ref vm.transaction, vm.tx_idx - ); + let sub_script = remove_signature(@self.sub_script, self.sig_bytes); + let sig_hash: u256 = sighash::calc_signature_hash::< + I, O, T + >(sub_script, self.hash_type, vm.transaction, vm.tx_idx); + + is_valid_signature(sig_hash, self.sig.r, self.sig.s, self.pub_key) + } +} + +pub trait BaseSegwitSigVerifierTrait< + I, + O, + T, + +EngineTransactionInputTrait, + +EngineTransactionOutputTrait, + +EngineTransactionTrait +> { + fn verify(ref self: BaseSigVerifier, ref vm: Engine) -> bool; +} + +impl BaseSegwitSigVerifierImpl< + I, + O, + T, + impl IEngineTransactionInput: EngineTransactionInputTrait, + impl IEngineTransactionOutput: EngineTransactionOutputTrait, + impl IEngineTransaction: EngineTransactionTrait< + T, I, O, IEngineTransactionInput, IEngineTransactionOutput + >, + +Drop, + +Drop, + +Drop +> of BaseSegwitSigVerifierTrait { + fn verify(ref self: BaseSigVerifier, ref vm: Engine) -> bool { + let sig_hashes = SigHashMidstateTrait::new(vm.transaction); + let sig_hash: u256 = sighash::calc_witness_signature_hash::< + I, O, T + >(@self.sub_script, @sig_hashes, self.hash_type, vm.transaction, vm.tx_idx, vm.amount); is_valid_signature(sig_hash, self.sig.r, self.sig.s, self.pub_key) } @@ -88,7 +131,19 @@ pub fn compare_data(script: @ByteArray, sig_bytes: @ByteArray, i: u32, push_data } // Check if hash_type obeys scrict encoding requirements. -pub fn check_hash_type_encoding>( +pub fn check_hash_type_encoding< + T, + +Drop, + I, + +Drop, + impl IEngineTransactionInputTrait: EngineTransactionInputTrait, + O, + +Drop, + impl IEngineTransactionOutputTrait: EngineTransactionOutputTrait, + impl IEngineTransactionTrait: EngineTransactionTrait< + T, I, O, IEngineTransactionInputTrait, IEngineTransactionOutputTrait + > +>( ref vm: Engine, mut hash_type: u32 ) -> Result<(), felt252> { if !vm.has_flag(ScriptFlags::ScriptVerifyStrictEncoding) { @@ -116,11 +171,22 @@ pub fn check_hash_type_encoding>( // @param vm A reference to the `Engine` that manages the execution context and provides // the necessary script verification flags. // @param sig_bytes The byte array containing the ECDSA signature that needs to be validated. -pub fn check_signature_encoding>( - ref vm: Engine, sig_bytes: @ByteArray + +pub fn check_signature_encoding< + T, + +Drop, + I, + +Drop, + impl IEngineTransactionInputTrait: EngineTransactionInputTrait, + O, + +Drop, + impl IEngineTransactionOutputTrait: EngineTransactionOutputTrait, + impl IEngineTransactionTrait: EngineTransactionTrait< + T, I, O, IEngineTransactionInputTrait, IEngineTransactionOutputTrait + > +>( + ref vm: Engine, sig_bytes: @ByteArray, strict_encoding: bool ) -> Result<(), felt252> { - let strict_encoding = vm.has_flag(ScriptFlags::ScriptVerifyStrictEncoding) - || vm.has_flag(ScriptFlags::ScriptVerifyDERSignatures); let low_s = vm.has_flag(ScriptFlags::ScriptVerifyLowS); // ASN.1 identifiers for sequence and integer types.* @@ -249,15 +315,26 @@ fn is_supported_pub_key_type(pk_bytes: @ByteArray) -> bool { } // Checks if a public key adheres to specific encoding rules based on the engine flags. -pub fn check_pub_key_encoding>( +pub fn check_pub_key_encoding< + T, + +Drop, + I, + +Drop, + impl IEngineTransactionInputTrait: EngineTransactionInputTrait, + O, + +Drop, + impl IEngineTransactionOutputTrait: EngineTransactionOutputTrait, + impl IEngineTransactionTrait: EngineTransactionTrait< + T, I, O, IEngineTransactionInputTrait, IEngineTransactionOutputTrait + > +>( ref vm: Engine, pk_bytes: @ByteArray ) -> Result<(), felt252> { - // TODO check compressed pubkey post segwit - // if vm.has_flag(ScriptFlags::ScriptVerifyWitnessPubKeyType) && - // vm.is_witness_version_active(BASE_SEGWIT_WITNESS_VERSION) && !is_compressed_pub_key(pk_bytes) - // { - // return Result::Err('only compressed keys are accepted post-segwit'); - // } + if vm.has_flag(ScriptFlags::ScriptVerifyWitnessPubKeyType) + && vm.is_witness_active(0) + && !is_compressed_pub_key(pk_bytes) { + return Result::Err(Error::WITNESS_PUBKEYTYPE); + } if !vm.has_flag(ScriptFlags::ScriptVerifyStrictEncoding) { return Result::Ok(()); @@ -278,7 +355,7 @@ pub fn check_pub_key_encoding>( // // @param pk_bytes The byte array representing the public key to be parsed. // @return A `Secp256k1Point` representing the public key on the secp256k1 elliptic curve. -pub fn parse_pub_key(pk_bytes: @ByteArray) -> Secp256k1Point { +pub fn parse_pub_key(pk_bytes: @ByteArray) -> Result { let mut pk_bytes_uncompressed = pk_bytes.clone(); if is_compressed_pub_key(pk_bytes) { @@ -289,20 +366,38 @@ pub fn parse_pub_key(pk_bytes: @ByteArray) -> Secp256k1Point { if pk_bytes[0] == 0x03 { parity = true; } - return Secp256Trait::::secp256_ec_get_point_from_x_syscall(pub_key, parity) - .unwrap_syscall() - .expect('Secp256k1Point: Invalid point.'); + return Result::Ok( + Secp256Trait::::secp256_ec_get_point_from_x_syscall(pub_key, parity) + .unwrap_syscall() + .expect('Secp256k1Point: Invalid point.') + ); } else { // Extract X coordinate and determine parity from last byte. + if pk_bytes_uncompressed.len() != 65 { + return Result::Err('Invalid public key length'); + } let pub_key: u256 = u256_from_byte_array_with_offset(@pk_bytes_uncompressed, 1, 32); let parity = !(pk_bytes_uncompressed[64] & 1 == 0); - return Secp256Trait::::secp256_ec_get_point_from_x_syscall(pub_key, parity) - .unwrap_syscall() - .expect('Secp256k1Point: Invalid point.'); + return Result::Ok( + Secp256Trait::::secp256_ec_get_point_from_x_syscall(pub_key, parity) + .unwrap_syscall() + .expect('Secp256k1Point: Invalid point.') + ); } } +pub fn parse_schnorr_pub_key(pk_bytes: @ByteArray) -> Secp256k1Point { + if pk_bytes.len() == 0 || pk_bytes.len() != 32 { + // TODO + panic!("invalid schnorr pubkey length"); + } + + let mut key_compressed: ByteArray = "\02"; + key_compressed.append(pk_bytes); + return parse_pub_key(@key_compressed).unwrap(); +} + // Parses a DER-encoded ECDSA signature byte array into a `Signature` struct. // // This function extracts the `r` and `s` values from a DER-encoded ECDSA signature (`sig_bytes`). @@ -364,28 +459,80 @@ pub fn parse_signature(sig_bytes: @ByteArray) -> Result { // Parses the public key and signature byte arrays based on consensus rules. // Returning a tuple containing the parsed public key, signature, and hash type. -pub fn parse_base_sig_and_pk>( +pub fn parse_base_sig_and_pk< + T, + +Drop, + I, + +Drop, + impl IEngineTransactionInputTrait: EngineTransactionInputTrait, + O, + +Drop, + impl IEngineTransactionOutputTrait: EngineTransactionOutputTrait, + impl IEngineTransactionTrait: EngineTransactionTrait< + T, I, O, IEngineTransactionInputTrait, IEngineTransactionOutputTrait + > +>( ref vm: Engine, pk_bytes: @ByteArray, sig_bytes: @ByteArray ) -> Result<(Secp256k1Point, Signature, u32), felt252> { + let verify_der = vm.has_flag(ScriptFlags::ScriptVerifyDERSignatures); + let strict_encoding = vm.has_flag(ScriptFlags::ScriptVerifyStrictEncoding) || verify_der; if sig_bytes.len() == 0 { - return Result::Err('empty signature'); + return if strict_encoding { + Result::Err(Error::SCRIPT_ERR_SIG_DER) + } else { + Result::Err('empty signature') + }; } + // TODO: strct encoding let hash_type_offset: usize = sig_bytes.len() - 1; let hash_type: u32 = sig_bytes[hash_type_offset].into(); + if let Result::Err(e) = check_hash_type_encoding(ref vm, hash_type) { + return if verify_der { + Result::Err(Error::SCRIPT_ERR_SIG_DER) + } else { + Result::Err(e) + }; + } + if let Result::Err(e) = check_signature_encoding(ref vm, sig_bytes, strict_encoding) { + return if verify_der { + Result::Err(Error::SCRIPT_ERR_SIG_DER) + } else { + Result::Err(e) + }; + } + + if let Result::Err(e) = check_pub_key_encoding(ref vm, pk_bytes) { + return if verify_der { + Result::Err(Error::SCRIPT_ERR_SIG_DER) + } else { + Result::Err(e) + }; + } - check_hash_type_encoding(ref vm, hash_type)?; - check_signature_encoding(ref vm, sig_bytes)?; - check_pub_key_encoding(ref vm, pk_bytes)?; + let pub_key = match parse_pub_key(pk_bytes) { + Result::Ok(key) => key, + Result::Err(e) => if verify_der { + return Result::Err(Error::SCRIPT_ERR_SIG_DER); + } else { + return Result::Err(e); + }, + }; - let pub_key = parse_pub_key(pk_bytes); - let sig = parse_signature(sig_bytes)?; + let sig = match parse_signature(sig_bytes) { + Result::Ok(signature) => signature, + Result::Err(e) => if verify_der { + return Result::Err(Error::SCRIPT_ERR_SIG_DER); + } else { + return Result::Err(e); + }, + }; Result::Ok((pub_key, sig, hash_type)) } // Removes the ECDSA signature from a given script. -pub fn remove_signature(script: ByteArray, sig_bytes: @ByteArray) -> ByteArray { +pub fn remove_signature(script: @ByteArray, sig_bytes: @ByteArray) -> @ByteArray { if script.len() == 0 || sig_bytes.len() == 0 { return script; } @@ -393,14 +540,15 @@ pub fn remove_signature(script: ByteArray, sig_bytes: @ByteArray) -> ByteArray { let mut processed_script: ByteArray = ""; let mut i: usize = 0; - while i < script.len() { + let script_len = script.len(); + while i < script_len { let push_data: u8 = script[i]; if push_data >= 8 && push_data <= 72 { let mut len: usize = push_data.into(); let mut found: bool = false; if len == sig_bytes.len() { - found = compare_data(@script, sig_bytes, i, push_data); + found = compare_data(script, sig_bytes, i, push_data); } if i + len <= script.len() { @@ -413,7 +561,7 @@ pub fn remove_signature(script: ByteArray, sig_bytes: @ByteArray) -> ByteArray { continue; } processed_script.append_byte(push_data); - while len != 0 && i - len < script.len() { + while len != 0 && i - len < script_len { processed_script.append_byte(script[i - len + 1]); len -= 1; }; @@ -423,5 +571,95 @@ pub fn remove_signature(script: ByteArray, sig_bytes: @ByteArray) -> ByteArray { i += 1; }; - processed_script + @processed_script +} + +#[derive(Drop)] +pub struct TaprootSigVerifier { + // public key as a point on the secp256k1 curve, used to verify the signature + pub_key: Secp256k1Point, + // ECDSA signature + sig: Signature, + // raw byte array of the signature + sig_bytes: @ByteArray, + // raw byte array of the public key + pk_bytes: @ByteArray, + // specifies how the transaction was hashed for signing + hash_type: u32, + // annex data used for taproot verification + annex: @ByteArray, +} + +pub trait TaprootSigVerifierTrait< + I, + O, + T, + +EngineTransactionInputTrait, + +EngineTransactionOutputTrait, + +EngineTransactionTrait +> { + fn new( + sig_bytes: @ByteArray, pk_bytes: @ByteArray, annex: @ByteArray + ) -> Result; + fn new_base(sig_bytes: @ByteArray, pk_bytes: @ByteArray) -> Result; + fn verify(ref self: TaprootSigVerifier) -> bool; + fn verify_base(ref self: TaprootSigVerifier) -> bool; +} + +pub impl TaprootSigVerifierImpl< + I, + O, + T, + impl IEngineTransactionInput: EngineTransactionInputTrait, + impl IEngineTransactionOutput: EngineTransactionOutputTrait, + impl IEngineTransaction: EngineTransactionTrait< + T, I, O, IEngineTransactionInput, IEngineTransactionOutput + >, + +Drop, + +Drop, + +Drop, +> of TaprootSigVerifierTrait { + fn new( + sig_bytes: @ByteArray, pk_bytes: @ByteArray, annex: @ByteArray + ) -> Result { + // TODO + Result::Ok( + TaprootSigVerifier { + pub_key: parse_pub_key(pk_bytes)?, + sig: parse_signature(sig_bytes)?, + sig_bytes, + pk_bytes, + hash_type: 0, + annex, + } + ) + // return Result::Err('TaprootSig not implemented'); + } + + fn new_base( + sig_bytes: @ByteArray, pk_bytes: @ByteArray + ) -> Result { + Result::Ok( + TaprootSigVerifier { + pub_key: parse_pub_key(pk_bytes)?, + sig: parse_signature(sig_bytes)?, + sig_bytes, + pk_bytes, + hash_type: 0, + annex: @"", + } + ) + // TODO + // return Result::Err('TaprootSig not implemented'); + } + + fn verify(ref self: TaprootSigVerifier) -> bool { + // TODO: implement taproot verification + return false; + } + + fn verify_base(ref self: TaprootSigVerifier) -> bool { + // TODO: implement taproot verification + return false; + } } diff --git a/packages/engine/src/signature/utils.cairo b/packages/engine/src/signature/utils.cairo index 5f0278bb..62c95685 100644 --- a/packages/engine/src/signature/utils.cairo +++ b/packages/engine/src/signature/utils.cairo @@ -1,8 +1,9 @@ use crate::signature::constants; use crate::transaction::{ - Transaction, OutPoint, TransactionInput, TransactionOutput, EngineTransactionTrait, - EngineTransactionInputTrait, EngineTransactionOutputTrait + EngineTransaction, EngineOutPoint, EngineTransactionInput, EngineTransactionOutput, + EngineTransactionTrait, EngineTransactionInputTrait, EngineTransactionOutputTrait }; +use crate::parser; use crate::opcodes::Opcode; // Removes `OP_CODESEPARATOR` opcodes from the `script`. @@ -12,14 +13,15 @@ pub fn remove_opcodeseparator(script: @ByteArray) -> @ByteArray { let mut i: usize = 0; // TODO: tokenizer/standardize script parsing - while i < script.len() { + let script_len = script.len(); + while i < script_len { let opcode = script[i]; // TODO: Error handling if opcode == Opcode::OP_CODESEPARATOR { i += 1; continue; } - let data_len = Opcode::data_len(i, script).unwrap(); + let data_len = parser::data_len(script, i).unwrap(); let end = i + data_len + 1; while i != end { parsed_script.append_byte(script[i]); @@ -41,26 +43,26 @@ pub fn remove_opcodeseparator(script: @ByteArray) -> @ByteArray { // @param hash_type The hash type that dictates how the transaction should be modified. // @return A modified copy of the transaction based on the provided hash type. pub fn transaction_procedure< - T, - +Drop, I, - +Drop, - impl IEngineTransactionInputTrait: EngineTransactionInputTrait, O, - +Drop, + T, + impl IEngineTransactionInputTrait: EngineTransactionInputTrait, impl IEngineTransactionOutputTrait: EngineTransactionOutputTrait, impl IEngineTransactionTrait: EngineTransactionTrait< T, I, O, IEngineTransactionInputTrait, IEngineTransactionOutputTrait - > + >, + +Drop, + +Drop, + +Drop, >( - ref transaction: T, index: u32, signature_script: ByteArray, hash_type: u32 -) -> Transaction { + transaction: @T, index: u32, signature_script: ByteArray, hash_type: u32 +) -> EngineTransaction { let hash_type_masked = hash_type & constants::SIG_HASH_MASK; let mut transaction_inputs_clone = array![]; for input in transaction .get_transaction_inputs() { - let new_transaction_input = TransactionInput { - previous_outpoint: OutPoint { + let new_transaction_input = EngineTransactionInput { + previous_outpoint: EngineOutPoint { txid: input.get_prevout_txid(), vout: input.get_prevout_vout() }, signature_script: input.get_signature_script().clone(), @@ -72,39 +74,40 @@ pub fn transaction_procedure< let mut transaction_outputs_clone = array![]; for output in transaction .get_transaction_outputs() { - let new_transaction_output = TransactionOutput { + let new_transaction_output = EngineTransactionOutput { value: output.get_value(), publickey_script: output.get_publickey_script().clone() }; transaction_outputs_clone.append(new_transaction_output); }; - let mut transaction_copy = Transaction { + let mut transaction_copy = EngineTransaction { version: transaction.get_version(), transaction_inputs: transaction_inputs_clone, transaction_outputs: transaction_outputs_clone, locktime: transaction.get_locktime() }; let mut i: usize = 0; - let mut transaction_input: Array = transaction_copy.transaction_inputs; - let mut processed_transaction_input: Array = ArrayTrait::< - TransactionInput + let mut transaction_input: Array = transaction_copy.transaction_inputs; + let mut processed_transaction_input: Array = ArrayTrait::< + EngineTransactionInput >::new(); - let mut processed_transaction_output: Array = ArrayTrait::< - TransactionOutput + let mut processed_transaction_output: Array = ArrayTrait::< + EngineTransactionOutput >::new(); - while i != transaction_input.len() { + let tx_input_len = transaction_input.len(); + while i != tx_input_len { // TODO: Optimize this - let mut temp_transaction_input: TransactionInput = transaction_input[i].clone(); + let mut temp_transaction_input: EngineTransactionInput = transaction_input[i].clone(); if hash_type_masked == constants::SIG_HASH_SINGLE && i < index { processed_transaction_output - .append(TransactionOutput { value: -1, publickey_script: "", }); + .append(EngineTransactionOutput { value: -1, publickey_script: "", }); } if i == index { processed_transaction_input .append( - TransactionInput { + EngineTransactionInput { previous_outpoint: temp_transaction_input.previous_outpoint, signature_script: signature_script.clone(), witness: temp_transaction_input.witness.clone(), @@ -122,7 +125,7 @@ pub fn transaction_procedure< } processed_transaction_input .append( - TransactionInput { + EngineTransactionInput { previous_outpoint: temp_transaction_input.previous_outpoint, signature_script: "", witness: temp_transaction_input.witness.clone(), @@ -137,7 +140,7 @@ pub fn transaction_procedure< transaction_copy.transaction_inputs = processed_transaction_input; if hash_type_masked == constants::SIG_HASH_NONE { - transaction_copy.transaction_outputs = ArrayTrait::::new(); + transaction_copy.transaction_outputs = ArrayTrait::::new(); } if hash_type_masked == constants::SIG_HASH_SINGLE { diff --git a/packages/engine/src/stack.cairo b/packages/engine/src/stack.cairo index 1adeb41e..588e0239 100644 --- a/packages/engine/src/stack.cairo +++ b/packages/engine/src/stack.cairo @@ -107,12 +107,13 @@ pub impl ScriptStackImpl of ScriptStackTrait { fn json(ref self: ScriptStack) { let mut i = 0; print!("["); - while i != self.len { + let end = self.len; + while i != end { let (entry, arr) = self.data.entry(i.into()); let arr = arr.deref(); print!("\"{}\"", bytecode_to_hex(@arr.clone())); self.data = entry.finalize(NullableTrait::new(arr)); - if i < self.len - 1 { + if i < end - 1 { print!(","); } i += 1; @@ -145,7 +146,8 @@ pub impl ScriptStackImpl of ScriptStackTrait { fn stack_to_span(ref self: ScriptStack) -> Span { let mut result = array![]; let mut i = 0; - while i != self.len { + let end = self.len; + while i != end { let (entry, arr) = self.data.entry(i.into()); let arr = arr.deref(); result.append(arr.clone()); diff --git a/packages/engine/src/taproot.cairo b/packages/engine/src/taproot.cairo new file mode 100644 index 00000000..4c8d8cf9 --- /dev/null +++ b/packages/engine/src/taproot.cairo @@ -0,0 +1,218 @@ +use crate::errors::Error; +use crate::transaction::{ + EngineTransactionTrait, EngineTransactionOutputTrait, EngineTransactionInputTrait +}; +use crate::signature::signature::parse_schnorr_pub_key; +use crate::signature::signature::{TaprootSigVerifierImpl}; +use starknet::secp256k1::{Secp256k1Point}; + +#[derive(Destruct)] +pub struct TaprootContext { + pub annex: @ByteArray, + pub code_sep: u32, + pub tapleaf_hash: u256, + sig_ops_budget: i32, + pub must_succeed: bool +} + +#[derive(Drop)] +pub struct ControlBlock { + internal_pubkey: Secp256k1Point, + output_key_y_is_odd: bool, + pub leaf_version: u8, + control_block: @ByteArray +} + +pub fn serialize_pub_key(pub_key: Secp256k1Point) -> @ByteArray { + // TODO: Check this is valid + let mut output_arr = array![]; + pub_key.serialize(ref output_arr); + let mut result = ""; + let mut i = 0; + let output_arr_len = output_arr.len(); + while i != output_arr_len { + result.append_word(*output_arr[i], 31); + i += 1; + }; + return @result; +} + +pub fn serialize_schnorr_pub_key(pub_key: Secp256k1Point) -> @ByteArray { + let pub_key_bytes: @ByteArray = serialize_pub_key(pub_key); + let mut result = ""; + let mut i = 1; + let pub_key_bytes_len = pub_key_bytes.len(); + while i != pub_key_bytes_len { + result.append_byte(pub_key_bytes[i]); + i += 1; + }; + return @result; +} + +pub fn compute_taproot_output_key(pubkey: @Secp256k1Point, script: @ByteArray) -> Secp256k1Point { + // TODO: Implement + return pubkey.clone(); +} + +pub fn tap_hash(sript: @ByteArray, version: u8) -> u256 { + // TODO: Implement + return 0; +} + +pub fn serialized_compressed(pub_key: Secp256k1Point) -> ByteArray { + // TODO: Implement + return ""; +} + +#[generate_trait()] +pub impl ControlBlockImpl of ControlBlockTrait { + // TODO: From parse + fn new( + internal_pubkey: Secp256k1Point, + output_key_y_is_odd: bool, + leaf_version: u8, + control_block: @ByteArray + ) -> ControlBlock { + ControlBlock { + internal_pubkey: internal_pubkey, + output_key_y_is_odd: output_key_y_is_odd, + leaf_version: leaf_version, + control_block: control_block + } + } + + fn root_hash(self: @ControlBlock, script: @ByteArray) -> ByteArray { + // TODO: Implement + return ""; + } + + fn verify_taproot_leaf( + self: @ControlBlock, witness_program: @ByteArray, script: @ByteArray + ) -> Result<(), felt252> { + let root_hash = self.root_hash(script); + let taproot_key = compute_taproot_output_key(self.internal_pubkey, @root_hash); + let expected_witness_program = serialize_pub_key(taproot_key); + if witness_program != expected_witness_program { + return Result::Err(Error::TAPROOT_INVALID_MERKLE_PROOF); + } + + let y_is_odd = serialized_compressed(taproot_key)[0] == 0x03; + if self.output_key_y_is_odd != @y_is_odd { + return Result::Err(Error::TAPROOT_PARITY_MISMATCH); + } + + return Result::Ok(()); + } +} + +const CONTROL_BLOCK_BASE_SIZE: u32 = 33; +const CONTROL_BLOCK_NODE_SIZE: u32 = 32; +const CONTROL_BLOCK_MAX_NODE_COUNT: u32 = 128; +const CONTROL_BLOCK_MAX_SIZE: u32 = CONTROL_BLOCK_BASE_SIZE + + (CONTROL_BLOCK_MAX_NODE_COUNT * CONTROL_BLOCK_NODE_SIZE); + +const SIG_OPS_DELTA: i32 = 50; +const BASE_CODE_SEP: u32 = 0xFFFFFFFF; +const TAPROOT_ANNEX_TAG: u8 = 0x50; +const TAPROOT_LEAF_MASK: u8 = 0xFE; +pub const BASE_LEAF_VERSION: u8 = 0xc0; + +#[generate_trait()] +pub impl TaprootContextImpl of TaprootContextTrait { + fn new(witness_size: i32) -> TaprootContext { + TaprootContext { + annex: @"", + code_sep: BASE_CODE_SEP, + tapleaf_hash: 0, + sig_ops_budget: SIG_OPS_DELTA + witness_size, + must_succeed: false + } + } + + fn empty() -> TaprootContext { + TaprootContext { + annex: @"", + code_sep: BASE_CODE_SEP, + tapleaf_hash: 0, + sig_ops_budget: SIG_OPS_DELTA, + must_succeed: false + } + } + + fn verify_taproot_spend< + T, + +Drop, + I, + +Drop, + impl IEngineTransactionInputTrait: EngineTransactionInputTrait, + O, + +Drop, + impl IEngineTransactionOutputTrait: EngineTransactionOutputTrait, + impl IEngineTransactionTrait: EngineTransactionTrait< + T, I, O, IEngineTransactionInputTrait, IEngineTransactionOutputTrait + > + >( + witness_program: @ByteArray, raw_sig: @ByteArray, tx: @T, tx_idx: u32 + ) -> Result<(), felt252> { + let witness: Span = tx.get_transaction_inputs()[tx_idx].get_witness(); + let mut annex = @""; + if is_annexed_witness(witness, witness.len()) { + annex = witness[witness.len() - 1]; + } + + let mut verifier = TaprootSigVerifierImpl::::new(raw_sig, witness_program, annex)?; + let is_valid = TaprootSigVerifierImpl::::verify(ref verifier); + if !is_valid { + return Result::Err(Error::TAPROOT_INVALID_SIG); + } + Result::Ok(()) + } + + fn use_ops_budget(ref self: TaprootContext) -> Result<(), felt252> { + self.sig_ops_budget -= SIG_OPS_DELTA; + + if self.sig_ops_budget < 0 { + return Result::Err(Error::TAPROOT_SIGOPS_EXCEEDED); + } + return Result::Ok(()); + } +} + +pub fn parse_control_block(control_block: @ByteArray) -> Result { + let control_block_len = control_block.len(); + if control_block_len < CONTROL_BLOCK_BASE_SIZE || control_block_len > CONTROL_BLOCK_MAX_SIZE { + return Result::Err(Error::TAPROOT_INVALID_CONTROL_BLOCK); + } + if (control_block_len - CONTROL_BLOCK_BASE_SIZE) % CONTROL_BLOCK_NODE_SIZE != 0 { + return Result::Err(Error::TAPROOT_INVALID_CONTROL_BLOCK); + } + + let leaf_version = control_block[0] & TAPROOT_LEAF_MASK; + let output_key_y_is_odd = (control_block[0] & 0x01) == 0x01; + + let mut raw_pubkey = ""; + let pubkey_end = 33; + let mut i = 1; + while i != pubkey_end { + raw_pubkey.append_byte(control_block[i]); + i += 1; + }; + let pubkey = parse_schnorr_pub_key(@raw_pubkey); + return Result::Ok( + ControlBlock { + internal_pubkey: pubkey, + output_key_y_is_odd: output_key_y_is_odd, + leaf_version: leaf_version, + control_block: control_block + } + ); +} + +pub fn is_annexed_witness(witness: Span, witness_len: usize) -> bool { + if witness_len < 2 { + return false; + } + + let last_elem = witness[witness_len - 1]; + return last_elem.len() > 0 && last_elem[0] == TAPROOT_ANNEX_TAG; +} diff --git a/packages/engine/src/transaction.cairo b/packages/engine/src/transaction.cairo index e6d87730..6d5562e9 100644 --- a/packages/engine/src/transaction.cairo +++ b/packages/engine/src/transaction.cairo @@ -1,70 +1,76 @@ use crate::errors::Error; use shinigami_utils::byte_array::{byte_array_value_at_le, byte_array_value_at_be, sub_byte_array}; -use shinigami_utils::bytecode::int_size_in_bytes; +use shinigami_utils::bytecode::{int_size_in_bytes, bytecode_to_hex}; use shinigami_utils::bit_shifts::shr; +use shinigami_utils::hash::double_sha256; // Tracks previous transaction outputs #[derive(Drop, Copy)] -pub struct OutPoint { +pub struct EngineOutPoint { pub txid: u256, pub vout: u32, } #[derive(Drop, Clone)] -pub struct TransactionInput { - pub previous_outpoint: OutPoint, +pub struct EngineTransactionInput { + pub previous_outpoint: EngineOutPoint, pub signature_script: ByteArray, pub witness: Array, pub sequence: u32, } #[derive(Drop, Clone)] -pub struct TransactionOutput { +pub struct EngineTransactionOutput { pub value: i64, pub publickey_script: ByteArray, } +// TODO: Move these EngineTransaction structs to the testing dir after +// signature::transaction_procedure cleanup #[derive(Drop, Clone)] -pub struct Transaction { +pub struct EngineTransaction { pub version: i32, - pub transaction_inputs: Array, - pub transaction_outputs: Array, + pub transaction_inputs: Array, + pub transaction_outputs: Array, pub locktime: u32, } -pub trait TransactionTrait { +pub trait EngineInternalTransactionTrait { fn new( version: i32, - transaction_inputs: Array, - transaction_outputs: Array, + transaction_inputs: Array, + transaction_outputs: Array, locktime: u32 - ) -> Transaction; - fn new_signed(script_sig: ByteArray) -> Transaction; - fn new_signed_witness(script_sig: ByteArray, witness: Array) -> Transaction; - fn btc_decode(raw: ByteArray, encoding: u32) -> Transaction; - fn deserialize(raw: ByteArray) -> Transaction; - fn deserialize_no_witness(raw: ByteArray) -> Transaction; - fn btc_encode(self: Transaction, encoding: u32) -> ByteArray; - fn serialize(self: Transaction) -> ByteArray; - fn serialize_no_witness(self: Transaction) -> ByteArray; + ) -> EngineTransaction; + fn new_signed(script_sig: ByteArray, pubkey_script: ByteArray) -> EngineTransaction; + fn new_signed_witness( + script_sig: ByteArray, pubkey_script: ByteArray, witness: Array, value: i64 + ) -> EngineTransaction; + fn btc_decode(raw: ByteArray, encoding: u32) -> EngineTransaction; + fn deserialize(raw: ByteArray) -> EngineTransaction; + fn deserialize_no_witness(raw: ByteArray) -> EngineTransaction; + fn btc_encode(self: EngineTransaction, encoding: u32) -> ByteArray; + fn serialize(self: EngineTransaction) -> ByteArray; + fn serialize_no_witness(self: EngineTransaction) -> ByteArray; fn calculate_block_subsidy(block_height: u32) -> i64; - fn is_coinbase(self: @Transaction) -> bool; + fn is_coinbase(self: @EngineTransaction) -> bool; fn validate_coinbase( - self: Transaction, block_height: u32, total_fees: i64 + self: EngineTransaction, block_height: u32, total_fees: i64 ) -> Result<(), felt252>; + fn print(self: @EngineTransaction); } pub const BASE_ENCODING: u32 = 0x01; pub const WITNESS_ENCODING: u32 = 0x02; -pub impl TransactionImpl of TransactionTrait { +pub impl EngineInternalTransactionImpl of EngineInternalTransactionTrait { fn new( version: i32, - transaction_inputs: Array, - transaction_outputs: Array, + transaction_inputs: Array, + transaction_outputs: Array, locktime: u32 - ) -> Transaction { - Transaction { + ) -> EngineTransaction { + EngineTransaction { version: version, transaction_inputs: transaction_inputs, transaction_outputs: transaction_outputs, @@ -72,53 +78,111 @@ pub impl TransactionImpl of TransactionTrait { } } - fn new_signed(script_sig: ByteArray) -> Transaction { - // TODO - let transaction = Transaction { + fn new_signed(script_sig: ByteArray, pubkey_script: ByteArray) -> EngineTransaction { + let coinbase_tx_inputs = array![ + EngineTransactionInput { + previous_outpoint: EngineOutPoint { txid: 0x0, vout: 0xffffffff, }, + signature_script: "\x00\x00", + witness: array![], + sequence: 0xffffffff, + } + ]; + let coinbase_tx_outputs = array![ + EngineTransactionOutput { value: 0, publickey_script: pubkey_script, } + ]; + let coinbase_tx = EngineTransaction { + version: 1, + transaction_inputs: coinbase_tx_inputs, + transaction_outputs: coinbase_tx_outputs, + locktime: 0, + }; + let coinbase_bytes = coinbase_tx.serialize_no_witness(); + let coinbase_txid = double_sha256(@coinbase_bytes); + let transaction = EngineTransaction { version: 1, transaction_inputs: array![ - TransactionInput { - previous_outpoint: OutPoint { txid: 0x0, vout: 0, }, + EngineTransactionInput { + previous_outpoint: EngineOutPoint { txid: coinbase_txid, vout: 0, }, signature_script: script_sig, witness: array![], sequence: 0xffffffff, } ], - transaction_outputs: array![], + transaction_outputs: array![ + EngineTransactionOutput { value: 0, publickey_script: "", } + ], locktime: 0, }; + // let transaction = EngineTransaction { + // version: 1, + // transaction_inputs: array![ + // EngineTransactionInput { + // previous_outpoint: EngineOutPoint { txid: 0x0, vout: 0, }, + // signature_script: script_sig, + // witness: array![], + // sequence: 0xffffffff, + // } + // ], + // transaction_outputs: array![], + // locktime: 0, + // }; transaction } - fn new_signed_witness(script_sig: ByteArray, witness: Array) -> Transaction { - // TODO - let transaction = Transaction { + fn new_signed_witness( + script_sig: ByteArray, pubkey_script: ByteArray, witness: Array, value: i64 + ) -> EngineTransaction { + let coinbase_tx_inputs = array![ + EngineTransactionInput { + previous_outpoint: EngineOutPoint { txid: 0x0, vout: 0xffffffff, }, + signature_script: "\x00\x00", + witness: array![], + sequence: 0xffffffff, + } + ]; + let coinbase_tx_outputs = array![ + EngineTransactionOutput { value: value, publickey_script: pubkey_script, } + ]; + let coinbase_tx = EngineTransaction { + version: 1, + transaction_inputs: coinbase_tx_inputs, + transaction_outputs: coinbase_tx_outputs, + locktime: 0, + }; + let coinbase_bytes = coinbase_tx.serialize_no_witness(); + let coinbase_txid = double_sha256(@coinbase_bytes); + let transaction = EngineTransaction { version: 1, transaction_inputs: array![ - TransactionInput { - previous_outpoint: OutPoint { txid: 0x0, vout: 0, }, + EngineTransactionInput { + previous_outpoint: EngineOutPoint { txid: coinbase_txid, vout: 0, }, signature_script: script_sig, witness: witness, sequence: 0xffffffff, } ], - transaction_outputs: array![], + transaction_outputs: array![ + EngineTransactionOutput { value: value, publickey_script: "", } + ], locktime: 0, }; transaction } // Deserialize a transaction from a byte array. - fn btc_decode(raw: ByteArray, encoding: u32) -> Transaction { + fn btc_decode(raw: ByteArray, encoding: u32) -> EngineTransaction { let mut offset: usize = 0; let version: i32 = byte_array_value_at_le(@raw, ref offset, 4).try_into().unwrap(); + if encoding == WITNESS_ENCODING { + // consume flags + offset += 2; + } // TODO: ReadVerIntBuf let input_len: u8 = byte_array_value_at_le(@raw, ref offset, 1).try_into().unwrap(); - // TODO: input_len = 0 -> segwit // TODO: Error handling and bounds checks // TODO: Byte orderings let mut i = 0; - let mut inputs: Array = array![]; + let mut inputs: Array = array![]; while i != input_len { let tx_id = u256 { high: byte_array_value_at_be(@raw, ref offset, 16).try_into().unwrap(), @@ -128,8 +192,8 @@ pub impl TransactionImpl of TransactionTrait { let script_len = byte_array_value_at_le(@raw, ref offset, 1).try_into().unwrap(); let script = sub_byte_array(@raw, ref offset, script_len); let sequence: u32 = byte_array_value_at_le(@raw, ref offset, 4).try_into().unwrap(); - let input = TransactionInput { - previous_outpoint: OutPoint { txid: tx_id, vout: vout }, + let input = EngineTransactionInput { + previous_outpoint: EngineOutPoint { txid: tx_id, vout: vout }, signature_script: script, witness: array![], sequence: sequence, @@ -140,36 +204,80 @@ pub impl TransactionImpl of TransactionTrait { let output_len: u8 = byte_array_value_at_le(@raw, ref offset, 1).try_into().unwrap(); let mut i = 0; - let mut outputs: Array = array![]; + let mut outputs: Array = array![]; while i != output_len { // TODO: negative values let value: i64 = byte_array_value_at_le(@raw, ref offset, 8).try_into().unwrap(); let script_len = byte_array_value_at_le(@raw, ref offset, 1).try_into().unwrap(); let script = sub_byte_array(@raw, ref offset, script_len); - let output = TransactionOutput { value: value, publickey_script: script, }; + let output = EngineTransactionOutput { value: value, publickey_script: script, }; outputs.append(output); i += 1; }; - // TODO: Witness + + let mut inputs_with_witness: Array = array![]; + + if encoding == WITNESS_ENCODING { + // one witness for each input + i = 0; + while i != input_len { + let witness_count: u8 = byte_array_value_at_le(@raw, ref offset, 1) + .try_into() + .unwrap(); + let mut j = 0; + let mut witness: Array = array![]; + while j != witness_count { + let script_len = byte_array_value_at_le(@raw, ref offset, 1) + .try_into() + .unwrap(); + let script = sub_byte_array(@raw, ref offset, script_len); + witness.append(script); + j += 1; + }; + // update Transaction Input + let input = inputs.at(i.into()); + let mut input_with_witness = input.clone(); + input_with_witness.witness = witness; + inputs_with_witness.append(input_with_witness); + i += 1; + }; + } let locktime: u32 = byte_array_value_at_le(@raw, ref offset, 4).try_into().unwrap(); - Transaction { - version: version, - transaction_inputs: inputs, - transaction_outputs: outputs, - locktime: locktime, + + if encoding == WITNESS_ENCODING { + EngineTransaction { + version: version, + transaction_inputs: inputs_with_witness, + transaction_outputs: outputs, + locktime: locktime, + } + } else { + EngineTransaction { + version: version, + transaction_inputs: inputs, + transaction_outputs: outputs, + locktime: locktime, + } } } - fn deserialize(raw: ByteArray) -> Transaction { - Self::btc_decode(raw, WITNESS_ENCODING) + fn deserialize(raw: ByteArray) -> EngineTransaction { + let mut offset: usize = 0; + let _version: i32 = byte_array_value_at_le(@raw, ref offset, 4).try_into().unwrap(); + let flags: u16 = byte_array_value_at_le(@raw, ref offset, 2).try_into().unwrap(); + if flags == 0x100 { + Self::btc_decode(raw, WITNESS_ENCODING) + } else { + Self::btc_decode(raw, BASE_ENCODING) + } } - fn deserialize_no_witness(raw: ByteArray) -> Transaction { + fn deserialize_no_witness(raw: ByteArray) -> EngineTransaction { Self::btc_decode(raw, BASE_ENCODING) } // Serialize the transaction data for hashing based on encoding used. - fn btc_encode(self: Transaction, encoding: u32) -> ByteArray { + fn btc_encode(self: EngineTransaction, encoding: u32) -> ByteArray { let mut bytes = ""; bytes.append_word_rev(self.version.into(), 4); // TODO: Witness encoding @@ -179,7 +287,7 @@ pub impl TransactionImpl of TransactionTrait { bytes.append_word_rev(input_len.into(), int_size_in_bytes(input_len)); let mut i: usize = 0; while i != input_len { - let input: @TransactionInput = self.transaction_inputs.at(i); + let input: @EngineTransactionInput = self.transaction_inputs.at(i); let input_txid: u256 = *input.previous_outpoint.txid; let vout: u32 = *input.previous_outpoint.vout; let script: @ByteArray = input.signature_script; @@ -201,7 +309,7 @@ pub impl TransactionImpl of TransactionTrait { bytes.append_word_rev(output_len.into(), int_size_in_bytes(output_len)); i = 0; while i != output_len { - let output: @TransactionOutput = self.transaction_outputs.at(i); + let output: @EngineTransactionOutput = self.transaction_outputs.at(i); let value: i64 = *output.value; let script: @ByteArray = output.publickey_script; let script_len: usize = script.len(); @@ -217,11 +325,11 @@ pub impl TransactionImpl of TransactionTrait { bytes } - fn serialize(self: Transaction) -> ByteArray { + fn serialize(self: EngineTransaction) -> ByteArray { self.btc_encode(WITNESS_ENCODING) } - fn serialize_no_witness(self: Transaction) -> ByteArray { + fn serialize_no_witness(self: EngineTransaction) -> ByteArray { self.btc_encode(BASE_ENCODING) } @@ -230,7 +338,7 @@ pub impl TransactionImpl of TransactionTrait { shr::(5000000000, halvings) } - fn is_coinbase(self: @Transaction) -> bool { + fn is_coinbase(self: @EngineTransaction) -> bool { if self.transaction_inputs.len() != 1 { return false; } @@ -244,7 +352,7 @@ pub impl TransactionImpl of TransactionTrait { } fn validate_coinbase( - self: Transaction, block_height: u32, total_fees: i64 + self: EngineTransaction, block_height: u32, total_fees: i64 ) -> Result<(), felt252> { if !self.is_coinbase() { return Result::Err(Error::INVALID_COINBASE); @@ -273,17 +381,50 @@ pub impl TransactionImpl of TransactionTrait { Result::Ok(()) } + + fn print(self: @EngineTransaction) { + println!("Version: {}", self.version); + println!("Locktime: {}", self.locktime); + println!("Inputs: {}", self.transaction_inputs.len()); + let mut i = 0; + while i != self.transaction_inputs.len() { + let input = self.transaction_inputs.at(i); + println!( + " Input {}: {} {}", i, input.previous_outpoint.txid, input.previous_outpoint.vout + ); + println!(" Txid: {}", input.previous_outpoint.txid); + println!(" Vout: {}", input.previous_outpoint.vout); + println!(" Script: {}", bytecode_to_hex(input.signature_script)); + println!(" Sequence: {}", input.sequence); + println!(" Witness: {}", input.witness.len()); + let mut j = 0; + while j != input.witness.len() { + println!(" Witness {}: {}", j, bytecode_to_hex(input.witness.at(j))); + j += 1; + }; + i += 1; + }; + println!("Outputs: {}", self.transaction_outputs.len()); + i = 0; + while i != self.transaction_outputs.len() { + let output = self.transaction_outputs.at(i); + println!(" Output {}: {}", i, output.value); + println!(" Script: {}", bytecode_to_hex(output.publickey_script)); + println!(" Value: {}", output.value); + i += 1; + }; + } } -impl TransactionDefault of Default { - fn default() -> Transaction { - let default_txin = TransactionInput { - previous_outpoint: OutPoint { txid: 0, vout: 0, }, +impl TransactionDefault of Default { + fn default() -> EngineTransaction { + let default_txin = EngineTransactionInput { + previous_outpoint: EngineOutPoint { txid: 0, vout: 0, }, signature_script: "", witness: array![], sequence: 0xffffffff, }; - let transaction = Transaction { + let transaction = EngineTransaction { version: 0, transaction_inputs: array![default_txin], transaction_outputs: array![], @@ -301,24 +442,26 @@ pub trait EngineTransactionInputTrait { fn get_sequence(self: @I) -> u32; } -pub impl EngineTransactionInputTraitInternalImpl of EngineTransactionInputTrait { - fn get_prevout_txid(self: @TransactionInput) -> u256 { +pub impl EngineTransactionInputTraitInternalImpl of EngineTransactionInputTrait< + EngineTransactionInput +> { + fn get_prevout_txid(self: @EngineTransactionInput) -> u256 { *self.previous_outpoint.txid } - fn get_prevout_vout(self: @TransactionInput) -> u32 { + fn get_prevout_vout(self: @EngineTransactionInput) -> u32 { *self.previous_outpoint.vout } - fn get_signature_script(self: @TransactionInput) -> @ByteArray { + fn get_signature_script(self: @EngineTransactionInput) -> @ByteArray { self.signature_script } - fn get_witness(self: @TransactionInput) -> Span { + fn get_witness(self: @EngineTransactionInput) -> Span { self.witness.span() } - fn get_sequence(self: @TransactionInput) -> u32 { + fn get_sequence(self: @EngineTransactionInput) -> u32 { *self.sequence } } @@ -329,13 +472,13 @@ pub trait EngineTransactionOutputTrait { } pub impl EngineTransactionOutputTraitInternalImpl of EngineTransactionOutputTrait< - TransactionOutput + EngineTransactionOutput > { - fn get_publickey_script(self: @TransactionOutput) -> @ByteArray { + fn get_publickey_script(self: @EngineTransactionOutput) -> @ByteArray { self.publickey_script } - fn get_value(self: @TransactionOutput) -> i64 { + fn get_value(self: @EngineTransactionOutput) -> i64 { *self.value } } @@ -350,25 +493,25 @@ pub trait EngineTransactionTrait< } pub impl EngineTransactionTraitInternalImpl of EngineTransactionTrait< - Transaction, - TransactionInput, - TransactionOutput, + EngineTransaction, + EngineTransactionInput, + EngineTransactionOutput, EngineTransactionInputTraitInternalImpl, EngineTransactionOutputTraitInternalImpl > { - fn get_version(self: @Transaction) -> i32 { + fn get_version(self: @EngineTransaction) -> i32 { *self.version } - fn get_transaction_inputs(self: @Transaction) -> Span { + fn get_transaction_inputs(self: @EngineTransaction) -> Span { self.transaction_inputs.span() } - fn get_transaction_outputs(self: @Transaction) -> Span { + fn get_transaction_outputs(self: @EngineTransaction) -> Span { self.transaction_outputs.span() } - fn get_locktime(self: @Transaction) -> u32 { + fn get_locktime(self: @EngineTransaction) -> u32 { *self.locktime } } diff --git a/packages/engine/src/witness.cairo b/packages/engine/src/witness.cairo index 0bea9798..dcc83b4b 100644 --- a/packages/engine/src/witness.cairo +++ b/packages/engine/src/witness.cairo @@ -1,4 +1,5 @@ use crate::opcodes::Opcode; +use crate::parser; use shinigami_utils::bytecode::hex_to_bytecode; fn byte_to_smallint(byte: u8) -> Result { @@ -17,8 +18,8 @@ pub fn parse_witness_program(witness: @ByteArray) -> Result<(i64, ByteArray), fe } let version: i64 = byte_to_smallint(witness[0])?; - let data_len = Opcode::data_len(1, witness)?; - let program: ByteArray = Opcode::data_at(2, data_len, witness)?; + let data_len = parser::data_len(witness, 1)?; + let program: ByteArray = parser::data_at(witness, 2, data_len)?; if !Opcode::is_canonical_push(witness[1], @program) { return Result::Err('Non-canonical witness program'); } @@ -35,16 +36,45 @@ pub fn parse_witness_input(input: ByteArray) -> Array { let mut witness_data: Array = array![]; let mut i = 0; let mut temp_witness: ByteArray = ""; - while i != input.len() { - if input[i] == ',' { + let witness_input_len = input.len(); + while i != witness_input_len { + let char = input[i].into(); + if char == ',' { let witness_bytes = hex_to_bytecode(@temp_witness); witness_data.append(witness_bytes); temp_witness = ""; } else { - temp_witness.append_byte(input[i]); + temp_witness.append_byte(char); } i += 1; }; + // Handle the last witness data + let witness_bytes = hex_to_bytecode(@temp_witness); + witness_data.append(witness_bytes); + + // TODO: Empty witness? witness_data } + +pub fn serialized_int_size(val: u64) -> i32 { + if val < 0xfd { + return 1; + } + if val <= 0xFFFF { + return 3; + } + if val <= 0xFFFFFFFF { + return 5; + } + return 9; +} + +pub fn serialized_witness_size(witness: Span) -> i32 { + let mut size = serialized_int_size(witness.len().into()); + for w in witness { + size += serialized_int_size(w.len().into()); + size += w.len().try_into().unwrap(); + }; + size +} diff --git a/packages/tests/README.md b/packages/tests/README.md new file mode 100644 index 00000000..e69de29b diff --git a/packages/tests/Scarb.toml b/packages/tests/Scarb.toml new file mode 100644 index 00000000..f73d320b --- /dev/null +++ b/packages/tests/Scarb.toml @@ -0,0 +1,15 @@ +[package] +name = "shinigami_tests" +version = "0.1.0" +edition = "2024_07" + +[dependencies] +shinigami_compiler = { path = "../compiler" } +shinigami_engine = { path = "../engine" } +shinigami_utils = { path = "../utils" } + +[dev-dependencies] +cairo_test.workspace = true + +[scripts] +lint = "scarb fmt" diff --git a/packages/tests/src/lib.cairo b/packages/tests/src/lib.cairo new file mode 100644 index 00000000..81644544 --- /dev/null +++ b/packages/tests/src/lib.cairo @@ -0,0 +1,22 @@ +pub mod validate; +pub mod utxo; +pub mod utils; +#[cfg(test)] +pub mod tests { + mod opcodes { + mod test_constants; + mod test_flow; + mod test_locktime; + mod test_stack; + mod test_splice; + mod test_bitwise; + mod test_arithmetic; + mod test_crypto; + mod test_reserved; + mod test_disabled; + } + mod test_coinbase; + mod test_transactions; + mod test_p2pk; + mod test_p2pkh; +} diff --git a/packages/engine/src/opcodes/tests/test_arithmetic.cairo b/packages/tests/src/tests/opcodes/test_arithmetic.cairo similarity index 99% rename from packages/engine/src/opcodes/tests/test_arithmetic.cairo rename to packages/tests/src/tests/opcodes/test_arithmetic.cairo index b8b374ed..5025cb4d 100644 --- a/packages/engine/src/opcodes/tests/test_arithmetic.cairo +++ b/packages/tests/src/tests/opcodes/test_arithmetic.cairo @@ -1,6 +1,6 @@ -use crate::errors::Error; -use crate::opcodes::tests::utils; -use crate::scriptnum::ScriptNum; +use shinigami_engine::errors::Error; +use shinigami_engine::scriptnum::ScriptNum; +use crate::utils; #[test] fn test_op_1add() { diff --git a/packages/engine/src/opcodes/tests/test_bitwise.cairo b/packages/tests/src/tests/opcodes/test_bitwise.cairo similarity index 86% rename from packages/engine/src/opcodes/tests/test_bitwise.cairo rename to packages/tests/src/tests/opcodes/test_bitwise.cairo index 46a1c2fa..b9489143 100644 --- a/packages/engine/src/opcodes/tests/test_bitwise.cairo +++ b/packages/tests/src/tests/opcodes/test_bitwise.cairo @@ -1,6 +1,6 @@ -use crate::errors::Error; -use crate::opcodes::tests::utils; -use crate::scriptnum::ScriptNum; +use shinigami_engine::errors::Error; +use shinigami_engine::scriptnum::ScriptNum; +use crate::utils; #[test] fn test_op_equal() { diff --git a/packages/engine/src/opcodes/tests/test_constants.cairo b/packages/tests/src/tests/opcodes/test_constants.cairo similarity index 98% rename from packages/engine/src/opcodes/tests/test_constants.cairo rename to packages/tests/src/tests/opcodes/test_constants.cairo index d6ea10c9..9757b7cf 100644 --- a/packages/engine/src/opcodes/tests/test_constants.cairo +++ b/packages/tests/src/tests/opcodes/test_constants.cairo @@ -1,10 +1,10 @@ -use crate::errors::Error; -use crate::opcodes::tests::utils::{ - test_compile_and_run, test_compile_and_run_err, check_expected_dstack, check_dstack_size -}; -use crate::scriptnum::ScriptNum; +use shinigami_engine::errors::Error; +use shinigami_engine::scriptnum::ScriptNum; use shinigami_utils::hex::int_to_hex; use shinigami_utils::bytecode::hex_to_bytecode; +use crate::utils::{ + test_compile_and_run, test_compile_and_run_err, check_expected_dstack, check_dstack_size +}; fn test_op_n(value: u8) { let program = format!("OP_{}", value); diff --git a/packages/engine/src/opcodes/tests/test_crypto.cairo b/packages/tests/src/tests/opcodes/test_crypto.cairo similarity index 99% rename from packages/engine/src/opcodes/tests/test_crypto.cairo rename to packages/tests/src/tests/opcodes/test_crypto.cairo index e253e365..a3560dbe 100644 --- a/packages/engine/src/opcodes/tests/test_crypto.cairo +++ b/packages/tests/src/tests/opcodes/test_crypto.cairo @@ -1,11 +1,11 @@ -use crate::opcodes::tests::utils::{ +use crate::utils::{ test_compile_and_run, check_expected_dstack, check_dstack_size, test_compile_and_run_with_tx_flags_err, mock_transaction_legacy_p2ms, test_compile_and_run_with_tx_err, test_compile_and_run_with_tx, mock_transaction_legacy_p2pkh }; -use crate::errors::Error; -use crate::scriptnum::ScriptNum; -use crate::scriptflags::ScriptFlags; +use shinigami_engine::errors::Error; +use shinigami_engine::scriptnum::ScriptNum; +use shinigami_engine::flags::ScriptFlags; use shinigami_utils::bytecode::hex_to_bytecode; #[test] diff --git a/packages/engine/src/opcodes/tests/test_disabled.cairo b/packages/tests/src/tests/opcodes/test_disabled.cairo similarity index 84% rename from packages/engine/src/opcodes/tests/test_disabled.cairo rename to packages/tests/src/tests/opcodes/test_disabled.cairo index c2d5ff0f..c62adbb0 100644 --- a/packages/engine/src/opcodes/tests/test_disabled.cairo +++ b/packages/tests/src/tests/opcodes/test_disabled.cairo @@ -1,5 +1,5 @@ -use crate::errors::Error; -use crate::opcodes::tests::utils; +use shinigami_engine::errors::Error; +use crate::utils; // TODO is there a way to define this as a const? fn disabled_opcodes() -> core::array::Array { @@ -26,7 +26,8 @@ fn disabled_opcodes() -> core::array::Array { fn test_op_code_disabled() { let disabled_opcodes = disabled_opcodes(); let mut i: usize = 0; - while i != disabled_opcodes.len() { + let disabled_opcodes_len = disabled_opcodes.len(); + while i != disabled_opcodes_len { let mut engine = utils::test_compile_and_run_err( disabled_opcodes.at(i).clone(), Error::OPCODE_DISABLED ); @@ -39,7 +40,8 @@ fn test_op_code_disabled() { fn test_disabled_opcodes_if_block() { let disabled_opcodes = disabled_opcodes(); let mut i: usize = 0; - while i != disabled_opcodes.len() { + let disabled_opcodes_len = disabled_opcodes.len(); + while i != disabled_opcodes_len { let program = format!( "OP_1 OP_IF {} OP_ELSE OP_DROP OP_ENDIF", disabled_opcodes.at(i).clone() ); @@ -53,7 +55,8 @@ fn test_disabled_opcodes_if_block() { fn test_disabled_opcodes_else_block() { let disabled_opcodes = disabled_opcodes(); let mut i: usize = 0; - while i != disabled_opcodes.len() { + let disabled_opcodes_len = disabled_opcodes.len(); + while i != disabled_opcodes_len { let program = format!( "OP_0 OP_IF OP_DROP OP_ELSE {} OP_ENDIF", disabled_opcodes.at(i).clone() ); @@ -68,7 +71,8 @@ fn test_disabled_opcodes_else_block() { fn test_disabled_opcode_in_unexecd_if_block() { let disabled_opcodes = disabled_opcodes(); let mut i: usize = 0; - while i != disabled_opcodes.len() { + let disabled_opcodes_len = disabled_opcodes.len(); + while i != disabled_opcodes_len { let program = format!( "OP_0 OP_IF {} OP_ELSE OP_DROP OP_ENDIF", disabled_opcodes.at(i).clone() ); diff --git a/packages/engine/src/opcodes/tests/test_flow.cairo b/packages/tests/src/tests/opcodes/test_flow.cairo similarity index 97% rename from packages/engine/src/opcodes/tests/test_flow.cairo rename to packages/tests/src/tests/opcodes/test_flow.cairo index 6564cacf..8952a9ac 100644 --- a/packages/engine/src/opcodes/tests/test_flow.cairo +++ b/packages/tests/src/tests/opcodes/test_flow.cairo @@ -1,6 +1,6 @@ -use crate::errors::Error; -use crate::opcodes::tests::utils; -use crate::scriptnum::ScriptNum; +use shinigami_engine::errors::Error; +use shinigami_engine::scriptnum::ScriptNum; +use crate::utils; #[test] fn test_op_nop() { diff --git a/packages/engine/src/opcodes/tests/test_locktime.cairo b/packages/tests/src/tests/opcodes/test_locktime.cairo similarity index 98% rename from packages/engine/src/opcodes/tests/test_locktime.cairo rename to packages/tests/src/tests/opcodes/test_locktime.cairo index 7b296c65..4951609b 100644 --- a/packages/engine/src/opcodes/tests/test_locktime.cairo +++ b/packages/tests/src/tests/opcodes/test_locktime.cairo @@ -1,6 +1,6 @@ -use crate::errors::Error; -use crate::opcodes::tests::utils; -use crate::scriptflags::ScriptFlags; +use shinigami_engine::errors::Error; +use shinigami_engine::flags::ScriptFlags; +use crate::utils; #[test] fn test_opcode_checklocktime() { diff --git a/packages/engine/src/opcodes/tests/test_reserved.cairo b/packages/tests/src/tests/opcodes/test_reserved.cairo similarity index 96% rename from packages/engine/src/opcodes/tests/test_reserved.cairo rename to packages/tests/src/tests/opcodes/test_reserved.cairo index 65627a1e..8f0378cd 100644 --- a/packages/engine/src/opcodes/tests/test_reserved.cairo +++ b/packages/tests/src/tests/opcodes/test_reserved.cairo @@ -1,5 +1,5 @@ -use crate::errors::Error; -use crate::opcodes::tests::utils; +use shinigami_engine::errors::Error; +use crate::utils; #[test] fn test_op_reserved() { diff --git a/packages/engine/src/opcodes/tests/test_splice.cairo b/packages/tests/src/tests/opcodes/test_splice.cairo similarity index 87% rename from packages/engine/src/opcodes/tests/test_splice.cairo rename to packages/tests/src/tests/opcodes/test_splice.cairo index bdc2dc47..3a829573 100644 --- a/packages/engine/src/opcodes/tests/test_splice.cairo +++ b/packages/tests/src/tests/opcodes/test_splice.cairo @@ -1,6 +1,6 @@ -use crate::errors::Error; -use crate::opcodes::tests::utils; -use crate::scriptnum::ScriptNum; +use shinigami_engine::errors::Error; +use shinigami_engine::scriptnum::ScriptNum; +use crate::utils; #[test] fn test_op_size_zero_item() { diff --git a/packages/engine/src/opcodes/tests/test_stack.cairo b/packages/tests/src/tests/opcodes/test_stack.cairo similarity index 99% rename from packages/engine/src/opcodes/tests/test_stack.cairo rename to packages/tests/src/tests/opcodes/test_stack.cairo index 52740319..f0a96f78 100644 --- a/packages/engine/src/opcodes/tests/test_stack.cairo +++ b/packages/tests/src/tests/opcodes/test_stack.cairo @@ -1,6 +1,6 @@ -use crate::errors::Error; -use crate::opcodes::tests::utils; -use crate::scriptnum::ScriptNum; +use shinigami_engine::errors::Error; +use shinigami_engine::scriptnum::ScriptNum; +use crate::utils; #[test] fn test_op_toaltstack() { diff --git a/packages/engine/src/tests/test.cairo b/packages/tests/src/tests/test.cairo similarity index 100% rename from packages/engine/src/tests/test.cairo rename to packages/tests/src/tests/test.cairo diff --git a/packages/engine/src/tests/test_coinbase.cairo b/packages/tests/src/tests/test_coinbase.cairo similarity index 83% rename from packages/engine/src/tests/test_coinbase.cairo rename to packages/tests/src/tests/test_coinbase.cairo index 50e3cf3c..4b4523c5 100644 --- a/packages/engine/src/tests/test_coinbase.cairo +++ b/packages/tests/src/tests/test_coinbase.cairo @@ -1,18 +1,23 @@ -use crate::transaction::TransactionTrait; +use shinigami_engine::transaction::EngineInternalTransactionTrait; use shinigami_utils::bytecode::hex_to_bytecode; #[test] fn test_block_subsidy_calculation() { - assert(TransactionTrait::calculate_block_subsidy(0) == 5000000000, 'Incorrect genesis subsidy'); assert( - TransactionTrait::calculate_block_subsidy(210000) == 2500000000, 'Incorrect halving subsidy' + EngineInternalTransactionTrait::calculate_block_subsidy(0) == 5000000000, + 'Incorrect genesis subsidy' ); assert( - TransactionTrait::calculate_block_subsidy(420000) == 1250000000, + EngineInternalTransactionTrait::calculate_block_subsidy(210000) == 2500000000, + 'Incorrect halving subsidy' + ); + assert( + EngineInternalTransactionTrait::calculate_block_subsidy(420000) == 1250000000, 'Incorrect 2nd halving subsidy' ); assert( - TransactionTrait::calculate_block_subsidy(13440000) == 0, 'Should be 0 after 64 halvings' + EngineInternalTransactionTrait::calculate_block_subsidy(13440000) == 0, + 'Should be 0 after 64 halvings' ); } @@ -22,7 +27,7 @@ fn test_validate_coinbase_block_0() { let raw_transaction_hex = "0x01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000"; let raw_transaction = hex_to_bytecode(@raw_transaction_hex); - let transaction = TransactionTrait::deserialize(raw_transaction); + let transaction = EngineInternalTransactionTrait::deserialize(raw_transaction); assert!( transaction.validate_coinbase(0, 5000000000).is_ok(), "Genesis block coinbase transaction invalid" @@ -35,7 +40,7 @@ fn test_validate_coinbase_block_1() { let raw_transaction_hex = "0x01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000"; let raw_transaction = hex_to_bytecode(@raw_transaction_hex); - let transaction = TransactionTrait::deserialize(raw_transaction); + let transaction = EngineInternalTransactionTrait::deserialize(raw_transaction); assert!( transaction.validate_coinbase(1, 5000000000).is_ok(), "Block 1 coinbase transaction invalid" ); @@ -47,7 +52,7 @@ fn test_validate_coinbase_block_150007() { let raw_transaction_hex = "0x01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804233fa04e028b12ffffffff0130490b2a010000004341047eda6bd04fb27cab6e7c28c99b94977f073e912f25d1ff7165d9c95cd9bbe6da7e7ad7f2acb09e0ced91705f7616af53bee51a238b7dc527f2be0aa60469d140ac00000000"; let raw_transaction = hex_to_bytecode(@raw_transaction_hex); - let transaction = TransactionTrait::deserialize(raw_transaction); + let transaction = EngineInternalTransactionTrait::deserialize(raw_transaction); assert!( transaction.validate_coinbase(150007, 350000).is_ok(), "Block 150007 coinbase transaction invalid" @@ -60,7 +65,7 @@ fn test_validate_coinbase_block_227835() { let raw_transaction_hex = "0x01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0f0479204f51024f09062f503253482fffffffff01da495f9500000000232103ddcdae35e28aca364daa1397612d2dafd891ee136d2ca5ab83faff6bc12ed67eac00000000"; let raw_transaction = hex_to_bytecode(@raw_transaction_hex); - let transaction = TransactionTrait::deserialize(raw_transaction); + let transaction = EngineInternalTransactionTrait::deserialize(raw_transaction); assert!( transaction.validate_coinbase(227835, 6050010).is_ok(), "Block 227835 coinbase transaction invalid" @@ -73,7 +78,7 @@ fn test_validate_coinbase_block_227836() { let raw_transaction_hex = "0x01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2703fc7903062f503253482f04ac204f510858029a11000003550d3363646164312f736c7573682f0000000001207e6295000000001976a914e285a29e0704004d4e95dbb7c57a98563d9fb2eb88ac00000000"; let raw_transaction = hex_to_bytecode(@raw_transaction_hex); - let transaction = TransactionTrait::deserialize(raw_transaction); + let transaction = EngineInternalTransactionTrait::deserialize(raw_transaction); assert!( transaction.validate_coinbase(227836, 6260000).is_ok(), "Block 227836 coinbase transaction invalid" @@ -86,7 +91,7 @@ fn test_validate_coinbase_block_400021() { let raw_transaction_hex = "0x01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff1b03951a0604f15ccf5609013803062b9b5a0100072f425443432f200000000001ebc31495000000001976a9142c30a6aaac6d96687291475d7d52f4b469f665a688ac00000000"; let raw_transaction = hex_to_bytecode(@raw_transaction_hex); - let transaction = TransactionTrait::deserialize(raw_transaction); + let transaction = EngineInternalTransactionTrait::deserialize(raw_transaction); assert!( transaction.validate_coinbase(400021, 1166059).is_ok(), "Block 400021 coinbase transaction invalid" @@ -99,7 +104,7 @@ fn test_validate_coinbase_block_481823() { let raw_transaction_hex = "0x01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4e031f5a070473319e592f4254432e434f4d2f4e59412ffabe6d6dcceb2a9d0444c51cabc4ee97a1a000036ca0cb48d25b94b78c8367d8b868454b0100000000000000c0309b21000008c5f8f80000ffffffff0291920b5d0000000017a914e083685a1097ce1ea9e91987ab9e94eae33d8a13870000000000000000266a24aa21a9ede6c99265a6b9e1d36c962fda0516b35709c49dc3b8176fa7e5d5f1f6197884b400000000"; let raw_transaction = hex_to_bytecode(@raw_transaction_hex); - let transaction = TransactionTrait::deserialize(raw_transaction); + let transaction = EngineInternalTransactionTrait::deserialize(raw_transaction); assert!( transaction.validate_coinbase(481823, 311039505).is_ok(), "Block 481823 coinbase transaction invalid" @@ -113,7 +118,7 @@ fn test_validate_coinbase_block_481824() { let raw_transaction_hex = "0x010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff6403205a07f4d3f9da09acf878c2c9c96c410d69758f0eae0e479184e0564589052e832c42899c867100010000000000000000db9901006052ce25d80acfde2f425443432f20537570706f7274202f4e59412f00000000000000000000000000000000000000000000025d322c57000000001976a9142c30a6aaac6d96687291475d7d52f4b469f665a688ac0000000000000000266a24aa21a9ed6c3c4dff76b5760d58694147264d208689ee07823e5694c4872f856eacf5a5d80120000000000000000000000000000000000000000000000000000000000000000000000000"; let raw_transaction = hex_to_bytecode(@raw_transaction_hex); - let transaction = TransactionTrait::deserialize(raw_transaction); + let transaction = EngineInternalTransactionTrait::deserialize(raw_transaction); assert!( transaction.validate_coinbase(481824, 212514269).is_ok(), "Block 481824 coinbase transaction invalid" @@ -127,7 +132,7 @@ fn test_validate_coinbase_block_538403() { let raw_transaction_hex = "0x010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff2503233708184d696e656420627920416e74506f6f6c373946205b8160a4256c0000946e0100ffffffff02f595814a000000001976a914edf10a7fac6b32e24daa5305c723f3de58db1bc888ac0000000000000000266a24aa21a9edfaa194df59043645ba0f58aad74bfd5693fa497093174d12a4bb3b0574a878db0120000000000000000000000000000000000000000000000000000000000000000000000000"; let raw_transaction = hex_to_bytecode(@raw_transaction_hex); - let transaction = TransactionTrait::deserialize(raw_transaction); + let transaction = EngineInternalTransactionTrait::deserialize(raw_transaction); assert!( transaction.validate_coinbase(538403, 6517).is_ok(), "Block 538403 coinbase transaction invalid" diff --git a/packages/engine/src/tests/test_p2pk.cairo b/packages/tests/src/tests/test_p2pk.cairo similarity index 88% rename from packages/engine/src/tests/test_p2pk.cairo rename to packages/tests/src/tests/test_p2pk.cairo index 7160a0c2..6ef8930e 100644 --- a/packages/engine/src/tests/test_p2pk.cairo +++ b/packages/tests/src/tests/test_p2pk.cairo @@ -1,5 +1,5 @@ -use crate::engine::{EngineImpl}; -use crate::transaction::TransactionTrait; +use shinigami_engine::engine::{EngineImpl}; +use shinigami_engine::transaction::EngineInternalTransactionTrait; use crate::validate; use crate::utxo::UTXO; use shinigami_utils::bytecode::hex_to_bytecode; @@ -14,10 +14,10 @@ fn test_compressed_pubkey() { let raw_transaction_hex = "0x010000000135655162f2df3af5e5f12b5b4b545e9069ed61897974622888b9c47e0f55e105000000006b483045022100bdd3796f6a6bb7f8ca42a70438a3150501f9ec760195b4d3314b1b4b21aac29402202f8479c9384a737bb323cd8600d9e3c5a379334a55acf7c3f4a4ca1eaaabe97e012103e49d61c45a729c427038b967df38459a2579a2c37057cf6a2efb2c3048f676aaffffffff018c0a000000000000232103203b768951584fe9af6d9d9e6ff26a5f76e453212f19ba163774182ab8057f3eac00000000"; let raw_transaction = hex_to_bytecode(@raw_transaction_hex); - let transaction = TransactionTrait::deserialize(raw_transaction); + let transaction = EngineInternalTransactionTrait::deserialize(raw_transaction); let utxo_hints = array![prev_out]; - let res = validate::validate_transaction(transaction, 0, utxo_hints); + let res = validate::validate_transaction(@transaction, 0, utxo_hints); assert!(res.is_ok(), "Transaction validation failed"); } @@ -32,10 +32,10 @@ fn test_block_181_tx_mainnet() { let raw_transaction_hex = "0x0100000001169e1e83e930853391bc6f35f605c6754cfead57cf8387639d3b4096c54f18f40100000048473044022027542a94d6646c51240f23a76d33088d3dd8815b25e9ea18cac67d1171a3212e02203baf203c6e7b80ebd3e588628466ea28be572fe1aaa3f30947da4763dd3b3d2b01ffffffff0200ca9a3b00000000434104b5abd412d4341b45056d3e376cd446eca43fa871b51961330deebd84423e740daa520690e1d9e074654c59ff87b408db903649623e86f1ca5412786f61ade2bfac005ed0b20000000043410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac00000000"; let raw_transaction = hex_to_bytecode(@raw_transaction_hex); - let transaction = TransactionTrait::deserialize(raw_transaction); + let transaction = EngineInternalTransactionTrait::deserialize(raw_transaction); let utxo_hints = array![prev_out]; - let res = validate::validate_transaction(transaction, 0, utxo_hints); + let res = validate::validate_transaction(@transaction, 0, utxo_hints); assert!(res.is_ok(), "Transaction validation failed"); } @@ -50,10 +50,10 @@ fn test_block_182_tx_mainnet() { let raw_transaction_hex = "0x0100000001be141eb442fbc446218b708f40caeb7507affe8acff58ed992eb5ddde43c6fa1010000004847304402201f27e51caeb9a0988a1e50799ff0af94a3902403c3ad4068b063e7b4d1b0a76702206713f69bd344058b0dee55a9798759092d0916dbbc3e592fee43060005ddc17401ffffffff0200e1f5050000000043410401518fa1d1e1e3e162852d68d9be1c0abad5e3d6297ec95f1f91b909dc1afe616d6876f92918451ca387c4387609ae1a895007096195a824baf9c38ea98c09c3ac007ddaac0000000043410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac00000000"; let raw_transaction = hex_to_bytecode(@raw_transaction_hex); - let transaction = TransactionTrait::deserialize(raw_transaction); + let transaction = EngineInternalTransactionTrait::deserialize(raw_transaction); let utxo_hints = array![prev_out]; - let res = validate::validate_transaction(transaction, 0, utxo_hints); + let res = validate::validate_transaction(@transaction, 0, utxo_hints); assert!(res.is_ok(), "Transaction validation failed"); } @@ -79,9 +79,9 @@ fn test_block_496_tx_mainnet() { let raw_transaction_hex = "0x010000000321f75f3139a013f50f315b23b0c9a2b6eac31e2bec98e5891c924664889942260000000049483045022100cb2c6b346a978ab8c61b18b5e9397755cbd17d6eb2fe0083ef32e067fa6c785a02206ce44e613f31d9a6b0517e46f3db1576e9812cc98d159bfdaf759a5014081b5c01ffffffff79cda0945903627c3da1f85fc95d0b8ee3e76ae0cfdc9a65d09744b1f8fc85430000000049483045022047957cdd957cfd0becd642f6b84d82f49b6cb4c51a91f49246908af7c3cfdf4a022100e96b46621f1bffcf5ea5982f88cef651e9354f5791602369bf5a82a6cd61a62501fffffffffe09f5fe3ffbf5ee97a54eb5e5069e9da6b4856ee86fc52938c2f979b0f38e82000000004847304402204165be9a4cbab8049e1af9723b96199bfd3e85f44c6b4c0177e3962686b26073022028f638da23fc003760861ad481ead4099312c60030d4cb57820ce4d33812a5ce01ffffffff01009d966b01000000434104ea1feff861b51fe3f5f8a3b12d0f4712db80e919548a80839fc47c6a21e66d957e9c5d8cd108c7a2d2324bad71f9904ac0ae7336507d785b17a2c115e427a32fac00000000"; let raw_transaction = hex_to_bytecode(@raw_transaction_hex); - let transaction = TransactionTrait::deserialize(raw_transaction); + let transaction = EngineInternalTransactionTrait::deserialize(raw_transaction); let utxo_hints = array![prev_out, prev_out2, prev_out3]; - let res = validate::validate_transaction(transaction, 0, utxo_hints); + let res = validate::validate_transaction(@transaction, 0, utxo_hints); assert!(res.is_ok(), "Transaction validation failed"); } diff --git a/packages/engine/src/tests/test_p2pkh.cairo b/packages/tests/src/tests/test_p2pkh.cairo similarity index 90% rename from packages/engine/src/tests/test_p2pkh.cairo rename to packages/tests/src/tests/test_p2pkh.cairo index 6bff22eb..b25b8f02 100644 --- a/packages/engine/src/tests/test_p2pkh.cairo +++ b/packages/tests/src/tests/test_p2pkh.cairo @@ -1,4 +1,4 @@ -use crate::transaction::TransactionTrait; +use shinigami_engine::transaction::EngineInternalTransactionTrait; use crate::utxo::UTXO; use crate::validate; use shinigami_utils::bytecode::hex_to_bytecode; @@ -10,7 +10,7 @@ fn test_p2pkh_transaction() { let raw_transaction_hex = "0x0100000002f60b5e96f09422354ab150b0e506c4bffedaf20216d30059cc5a3061b4c83dff000000004a493046022100e26d9ff76a07d68369e5782be3f8532d25ecc8add58ee256da6c550b52e8006b022100b4431f5a9a4dcb51cbdcaae935218c0ae4cfc8aa903fe4e5bac4c208290b7d5d01fffffffff7272ef43189f5553c2baea50f59cde99b3220fd518884d932016d055895b62d000000004a493046022100a2ab7cdc5b67aca032899ea1b262f6e8181060f5a34ee667a82dac9c7b7db4c3022100911bc945c4b435df8227466433e56899fbb65833e4853683ecaa12ee840d16bf01ffffffff0100e40b54020000001976a91412ab8dc588ca9d5787dde7eb29569da63c3a238c88ac00000000"; let raw_transaction = hex_to_bytecode(@raw_transaction_hex); - let transaction = TransactionTrait::deserialize(raw_transaction); + let transaction = EngineInternalTransactionTrait::deserialize(raw_transaction); let prevout_pk_script_1 = "0x4104c9560dc538db21476083a5c65a34c7cc219960b1e6f27a87571cd91edfd00dac16dca4b4a7c4ab536f85bc263b3035b762c5576dc6772492b8fb54af23abff6dac"; @@ -24,7 +24,7 @@ fn test_p2pkh_transaction() { }; let utxo_hints = array![prevout_1, prevout_2]; - let res = validate::validate_transaction(transaction, 0, utxo_hints); + let res = validate::validate_transaction(@transaction, 0, utxo_hints); assert!(res.is_ok(), "Transaction validation failed"); } @@ -35,7 +35,7 @@ fn test_p2pkh_transaction_spend() { let raw_transaction_hex = "0x01000000030dd7891efbf67da47c651531db8aab3144ed7a524e4ae1e30b773525e27ddd7b000000004948304502206f6a68710a51f77e5a1fa4d1037a23a76723724a51fd54710949e0189ee02dfa022100dad3454ade12fe84f3818e14c41ec2e02bbb154dd3136a094cdf86f67ebbe0b601ffffffff16851666962e37a75a246101f2e340c628b1db3c045d4d3cfb2d1c0f58f97c6f000000008b48304502203f004eeed0cef2715643e2f25a27a28f3c578e94c7f0f6a4df104e7d163f7f8f022100b8b248c1cfd8f77a0365107a9511d759b7544d979dd152a955c867afac0ef7860141044d05240cfbd8a2786eda9dadd520c1609b8593ff8641018d57703d02ba687cf2f187f0cee2221c3afb1b5ff7888caced2423916b61444666ca1216f26181398cffffffffffda5d38e91fd9a0d92872d51f83cb746fc7bf5d3ff13402f8d0d5ed60ddc79c0000000049483045022100b6fd43f2fa16e092678283f64d2e08fb2070b4af2b3ddfb9ca3c5e238288acaa02200c5a28e0a4fc1a540f6eeb30ccc4788050eae46964fe33ccb4500c3de1320c2501ffffffff02c0c62d00000000001976a91417194e1bd175fb5b1b2a1f9d221f6f5c29e1928388ac00c817a8040000001976a91465bda9b05f7e9a8f96a7f4ba0996a877708ef90888ac00000000"; let raw_transaction = hex_to_bytecode(@raw_transaction_hex); - let transaction = TransactionTrait::deserialize(raw_transaction); + let transaction = EngineInternalTransactionTrait::deserialize(raw_transaction); let prevout_pk_script_0 = "0x4104889fcdfd7c5430d13f1eb5f508e2e87f38d2406fad8425a824e032ccb371ef62465331e1a6334d7c3770a2ad2a958e740130343399d01dbd87426db850f9faf9ac"; @@ -64,7 +64,7 @@ fn test_p2pkh_transaction_spend() { let utxo_hints = array![prev_out0, prev_out1, prev_out2]; // Run Shinigami and validate the transaction execution - let res = validate::validate_transaction(transaction, 0, utxo_hints); + let res = validate::validate_transaction(@transaction, 0, utxo_hints); assert!(res.is_ok(), "Transaction validation failed"); } @@ -81,7 +81,7 @@ fn test_block_770000_p2pkh_transaction() { let raw_transaction_hex = "0x0200000001c3cbbd0f9ac1f59225df1381c10c4b104ed7d78beef73e89cbd163c8d98b729e000000006a47304402202acb8afaa5745d1fd99dab6e74d89ee679daca1973796f61916e6e27905cd01b022067120362c1145cdd2a2de182435618b3c356a72849718997e5546d62ea9925fb012102e34755efb7b73a51f0a2facc10c9aab73b99a3f676c60fe5a7e865c75d61cce3feffffff02acf15608020000001976a9149ee1cd0c085b88bd7b22e44abe52734e0a61c94288ac404b4c00000000001976a914a7e9478b4f77c490c32472cfe8ad672d24fc77a888accfbf0b00"; let raw_transaction = hex_to_bytecode(@raw_transaction_hex); - let transaction = TransactionTrait::deserialize(raw_transaction); + let transaction = EngineInternalTransactionTrait::deserialize(raw_transaction); let prevout_pk_script = "0x76a9140900bb14c7cb6a52fd8a22fd68a5986eb193c9f588ac"; let prevout = UTXO { @@ -89,6 +89,6 @@ fn test_block_770000_p2pkh_transaction() { }; let utxo_hints = array![prevout]; - let res = validate::validate_transaction(transaction, 0, utxo_hints); + let res = validate::validate_transaction(@transaction, 0, utxo_hints); assert!(res.is_ok(), "Transaction validation failed"); } diff --git a/packages/engine/src/tests/test_transactions.cairo b/packages/tests/src/tests/test_transactions.cairo similarity index 76% rename from packages/engine/src/tests/test_transactions.cairo rename to packages/tests/src/tests/test_transactions.cairo index b94a69c0..31003cb8 100644 --- a/packages/engine/src/tests/test_transactions.cairo +++ b/packages/tests/src/tests/test_transactions.cairo @@ -1,4 +1,4 @@ -use crate::transaction::TransactionTrait; +use shinigami_engine::transaction::EngineInternalTransactionTrait; use crate::utxo::UTXO; use crate::validate; use shinigami_utils::byte_array::u256_from_byte_array_with_offset; @@ -13,7 +13,7 @@ fn test_deserialize_transaction() { let raw_transaction_hex = "0x010000000291056d7ab3e99f9506f248783e0801c9039082d7d876dd45a8ab1f0a166226e2000000008c493046022100a3deff7d28eca94e018cfafcf4e705cc6bb56ce1dab83a6377e6e97d28d305d90221008cfc8d40bb8e336f5210a4197760f6b9650ae6ec4682cc1626841d9c87d1b0f20141049305a94c5b8e71d8be2a2d7188d74cb38affc9dc83ab77cc2fedf7c03a82a56175b9c335ce4546a943a2215a9c04757f08c2cc97f731a208ea767119050e0b97ffffffff465345e66a84047bf58a3787456d8023c38e04734c72d7f7039b9220ac503b6e000000008a47304402202ff5fe06ff3ee680e069cd28ff3ed9a60050ba52ed811a739a29b81e3667074602203c0d1b63d0c495ee1b63886e42c2db0c4cb041ce0c957ad7febe0fbcd23498ee014104cc2cb6eb11b7b504e1aa2826cf8ce7568bc757d7f58ab1eaa0b5e6945ccdcc5b111c0c1163a28037b89501e0b83e3fdceb22a2fd80533e5211acac060b17b2a4ffffffff0243190600000000001976a914a2baed4cdeda71053537312ee32cf0ab9f22cf1888acc0451b11000000001976a914f3e0b1ca6d94a95e1f3683ea6f3d2b563ad475e688ac00000000"; let raw_transaction = hex_to_bytecode(@raw_transaction_hex); - let transaction = TransactionTrait::deserialize(raw_transaction); + let transaction = EngineInternalTransactionTrait::deserialize(raw_transaction); assert_eq!(transaction.version, 1, "Version is not correct"); assert_eq!(transaction.transaction_inputs.len(), 2, "Transaction inputs length is not correct"); @@ -74,7 +74,7 @@ fn test_deserialize_first_p2pkh_transaction() { let raw_transaction_hex = "0x0100000002f60b5e96f09422354ab150b0e506c4bffedaf20216d30059cc5a3061b4c83dff000000004a493046022100e26d9ff76a07d68369e5782be3f8532d25ecc8add58ee256da6c550b52e8006b022100b4431f5a9a4dcb51cbdcaae935218c0ae4cfc8aa903fe4e5bac4c208290b7d5d01fffffffff7272ef43189f5553c2baea50f59cde99b3220fd518884d932016d055895b62d000000004a493046022100a2ab7cdc5b67aca032899ea1b262f6e8181060f5a34ee667a82dac9c7b7db4c3022100911bc945c4b435df8227466433e56899fbb65833e4853683ecaa12ee840d16bf01ffffffff0100e40b54020000001976a91412ab8dc588ca9d5787dde7eb29569da63c3a238c88ac00000000"; let raw_transaction = hex_to_bytecode(@raw_transaction_hex); - let transaction = TransactionTrait::deserialize(raw_transaction); + let transaction = EngineInternalTransactionTrait::deserialize(raw_transaction); assert_eq!(transaction.version, 1, "Version is not correct"); assert_eq!(transaction.transaction_inputs.len(), 2, "Transaction inputs length is not correct"); @@ -121,6 +121,46 @@ fn test_deserialize_first_p2pkh_transaction() { assert_eq!(transaction.locktime, 0, "Lock time is not correct"); } +#[test] +fn test_deserialize_p2wsh_transaction() { + // https://learnmeabitcoin.com/explorer/tx/64f427122f7951687aea608b5474509a30616d4e5773a83bc1ed8b8271ad1991 + let raw_transaction_hex = + "0x020000000001018a39b5cdd48c7d45a31a89cd675a95f5de78aebeeda1e55ac35d7110c3bacfc60000000000ffffffff01204e0000000000001976a914ee63c8c790952de677d1f8019c9474d84098d6e188ac0202123423aa20a23421f2ba909c885a3077bb6f8eb4312487797693bbcfe7e311f797e3c5b8fa8700000000"; + let raw_transaction = hex_to_bytecode(@raw_transaction_hex); + let transaction = EngineInternalTransactionTrait::deserialize(raw_transaction); + + assert_eq!(transaction.version, 2, "Version is not correct"); + assert_eq!(transaction.transaction_inputs.len(), 1, "Transaction inputs length is not correct"); + let input0 = transaction.transaction_inputs[0]; + let expected_txid_hex = "0x8a39b5cdd48c7d45a31a89cd675a95f5de78aebeeda1e55ac35d7110c3bacfc6"; + let expected_txid = hex_to_bytecode(@expected_txid_hex); + let expected_witness_1_hex = "0x1234"; + let expected_witness_1 = hex_to_bytecode(@expected_witness_1_hex); + let expected_witness_2_hex = + "0xaa20a23421f2ba909c885a3077bb6f8eb4312487797693bbcfe7e311f797e3c5b8fa87"; + let expected_witness_2 = hex_to_bytecode(@expected_witness_2_hex); + + assert_eq!(input0.previous_outpoint.vout, @0, "Outpoint vout on input 1 is not correct"); + assert_eq!( + input0.previous_outpoint.txid, + @u256_from_byte_array_with_offset(@expected_txid, 0, 32), + "Outpoint txid on input 1 is not correct" + ); + assert_eq!(input0.signature_script.len(), 0, "Script sig on input 1 is not empty"); + assert_eq!(input0.witness.len(), 2, "Witness length on input 1 is not correct"); + assert_eq!(input0.witness[0], @expected_witness_1, "Witness 1 on input 1 is not correct"); + assert_eq!(input0.witness[1], @expected_witness_2, "Witness 2 on input 1 is not correct"); + assert_eq!(input0.sequence, @0xFFFFFFFF, "Sequence on input 1 is not correct"); + + let output0 = transaction.transaction_outputs[0]; + assert_eq!(output0.value, @20000, "Output 1 value is not correct"); + let expected_pk_script_hex = "0x76a914ee63c8c790952de677d1f8019c9474d84098d6e188ac"; + let expected_pk_script = hex_to_bytecode(@expected_pk_script_hex); + assert_eq!(output0.publickey_script, @expected_pk_script, "Output 1 pk_script is not correct"); + + assert_eq!(transaction.locktime, 0, "Lock time is not correct"); +} + #[test] fn test_deserialize_coinbase_transaction() { // TODO } @@ -132,7 +172,7 @@ fn test_validate_transaction() { let raw_transaction_hex = "0x0100000001c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25857fcd3704000000004847304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901ffffffff0200ca9a3b00000000434104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac00286bee0000000043410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac00000000"; let raw_transaction = hex_to_bytecode(@raw_transaction_hex); - let transaction = TransactionTrait::deserialize(raw_transaction); + let transaction = EngineInternalTransactionTrait::deserialize(raw_transaction); // Setup UTXO hints ( previous valid outputs used to execute this transaction ) let prevout_pk_script = @@ -143,6 +183,6 @@ fn test_validate_transaction() { let utxo_hints = array![prev_out]; // Run Shinigami and validate the transaction execution - let res = validate::validate_transaction(transaction, 0, utxo_hints); + let res = validate::validate_transaction(@transaction, 0, utxo_hints); assert!(res.is_ok(), "Transaction validation failed"); } diff --git a/packages/engine/src/opcodes/tests/utils.cairo b/packages/tests/src/utils.cairo similarity index 53% rename from packages/engine/src/opcodes/tests/utils.cairo rename to packages/tests/src/utils.cairo index a8827d57..ff58dec4 100644 --- a/packages/engine/src/opcodes/tests/utils.cairo +++ b/packages/tests/src/utils.cairo @@ -1,25 +1,30 @@ use shinigami_compiler::compiler::CompilerImpl; -use crate::engine::{Engine, EngineInternalImpl, EngineInternalTrait}; -use crate::transaction::{Transaction, TransactionInput, TransactionOutput, OutPoint}; +use shinigami_engine::engine::{Engine, EngineImpl, EngineInternalTrait}; +use shinigami_engine::hash_cache::HashCacheImpl; +use shinigami_engine::transaction::{ + EngineTransaction, EngineTransactionInput, EngineTransactionOutput, EngineOutPoint +}; // Runs a basic bitcoin script as the script_pubkey with empty script_sig -pub fn test_compile_and_run(program: ByteArray) -> Engine { +pub fn test_compile_and_run(program: ByteArray) -> Engine { let mut compiler = CompilerImpl::new(); let bytecode = compiler.compile(program).unwrap(); // TODO: Nullable - let mut engine = EngineInternalImpl::new(@bytecode, Default::default(), 0, 0, 0).unwrap(); - let res = EngineInternalTrait::execute(ref engine); + let hash_cache = HashCacheImpl::new(Default::default()); + let mut engine = EngineImpl::new(@bytecode, Default::default(), 0, 0, 0, @hash_cache).unwrap(); + let res = engine.execute(); assert!(res.is_ok(), "Execution of the program failed"); engine } // Runs a bitcoin script `program` as script_pubkey with corresponding `transaction` pub fn test_compile_and_run_with_tx( - program: ByteArray, transaction: Transaction -) -> Engine { + program: ByteArray, transaction: EngineTransaction +) -> Engine { let mut compiler = CompilerImpl::new(); let mut bytecode = compiler.compile(program).unwrap(); - let mut engine = EngineInternalImpl::new(@bytecode, transaction, 0, 0, 0).unwrap(); + let hash_cache = HashCacheImpl::new(@transaction); + let mut engine = EngineImpl::new(@bytecode, @transaction, 0, 0, 0, @hash_cache).unwrap(); let res = engine.execute(); assert!(res.is_ok(), "Execution of the program failed"); engine @@ -27,84 +32,90 @@ pub fn test_compile_and_run_with_tx( // Runs a bitcoin script `program` as script_pubkey with corresponding `transaction` and 'flags' pub fn test_compile_and_run_with_tx_flags( - program: ByteArray, transaction: Transaction, flags: u32 -) -> Engine { + program: ByteArray, transaction: EngineTransaction, flags: u32 +) -> Engine { let mut compiler = CompilerImpl::new(); let mut bytecode = compiler.compile(program).unwrap(); - let mut engine = EngineInternalImpl::new(@bytecode, transaction, 0, flags, 0).unwrap(); + let hash_cache = HashCacheImpl::new(@transaction); + let mut engine = EngineImpl::new(@bytecode, @transaction, 0, flags, 0, @hash_cache).unwrap(); let res = engine.execute(); assert!(res.is_ok(), "Execution of the program failed"); engine } // Runs a bitcoin script `program` as script_pubkey with empty script_sig expecting an error -pub fn test_compile_and_run_err(program: ByteArray, expected_err: felt252) -> Engine { +pub fn test_compile_and_run_err( + program: ByteArray, expected_err: felt252 +) -> Engine { let mut compiler = CompilerImpl::new(); let bytecode = compiler.compile(program).unwrap(); - let mut engine = EngineInternalImpl::new(@bytecode, Default::default(), 0, 0, 0).unwrap(); + let hash_cache = HashCacheImpl::new(Default::default()); + let mut engine = EngineImpl::new(@bytecode, Default::default(), 0, 0, 0, @hash_cache).unwrap(); let res = engine.execute(); assert!(res.is_err(), "Execution of the program did not fail as expected"); let err = res.unwrap_err(); - assert_eq!(err, expected_err, "Program did not return the expected error"); + assert!(err == expected_err, "Program did not return the expected error"); engine } // Runs a bitcoin script `program` as script_pubkey with corresponding `transaction` expecting an // error pub fn test_compile_and_run_with_tx_err( - program: ByteArray, transaction: Transaction, expected_err: felt252 -) -> Engine { + program: ByteArray, transaction: EngineTransaction, expected_err: felt252 +) -> Engine { let mut compiler = CompilerImpl::new(); let mut bytecode = compiler.compile(program).unwrap(); - let mut engine = EngineInternalImpl::new(@bytecode, transaction, 0, 0, 0).unwrap(); + let hash_cache = HashCacheImpl::new(@transaction); + let mut engine = EngineImpl::new(@bytecode, @transaction, 0, 0, 0, @hash_cache).unwrap(); let res = engine.execute(); assert!(res.is_err(), "Execution of the program did not fail as expected"); let err = res.unwrap_err(); - assert_eq!(err, expected_err, "Program did not return the expected error"); + assert!(err == expected_err, "Program did not return the expected error"); engine } // Runs a bitcoin script `program` as script_pubkey with corresponding `transaction` and 'flags' // expecting an error pub fn test_compile_and_run_with_tx_flags_err( - program: ByteArray, transaction: Transaction, flags: u32, expected_err: felt252 -) -> Engine { + program: ByteArray, transaction: EngineTransaction, flags: u32, expected_err: felt252 +) -> Engine { let mut compiler = CompilerImpl::new(); let mut bytecode = compiler.compile(program).unwrap(); - let mut engine = EngineInternalImpl::new(@bytecode, transaction, 0, flags, 0).unwrap(); + let hash_cache = HashCacheImpl::new(@transaction); + let mut engine = EngineImpl::new(@bytecode, @transaction, 0, flags, 0, @hash_cache).unwrap(); let res = engine.execute(); assert!(res.is_err(), "Execution of the program did not fail as expected"); let err = res.unwrap_err(); - assert_eq!(err, expected_err, "Program did not return the expected error"); + assert!(err == expected_err, "Program did not return the expected error"); engine } -pub fn check_dstack_size(ref engine: Engine, expected_size: usize) { +pub fn check_dstack_size(ref engine: Engine, expected_size: usize) { let dstack = engine.get_dstack(); - assert_eq!(dstack.len(), expected_size, "Dstack size is not as expected"); + assert!(dstack.len() == expected_size, "Dstack size is not as expected"); } -pub fn check_astack_size(ref engine: Engine, expected_size: usize) { +pub fn check_astack_size(ref engine: Engine, expected_size: usize) { let astack = engine.get_astack(); - assert_eq!(astack.len(), expected_size, "Astack size is not as expected"); + assert!(astack.len() == expected_size, "Astack size is not as expected"); } -pub fn check_expected_dstack(ref engine: Engine, expected: Span) { +pub fn check_expected_dstack(ref engine: Engine, expected: Span) { let dstack = engine.get_dstack(); - assert_eq!(dstack, expected, "Dstack is not as expected"); + assert!(dstack == expected, "Dstack is not as expected"); } -pub fn check_expected_astack(ref engine: Engine, expected: Span) { +pub fn check_expected_astack(ref engine: Engine, expected: Span) { let astack = engine.get_astack(); - assert_eq!(astack, expected, "Astack is not as expected"); + assert!(astack == expected, "Astack is not as expected"); } pub fn mock_transaction_input_with( - outpoint: OutPoint, script_sig: ByteArray, witness: Array, sequence: u32 -) -> TransactionInput { + outpoint: EngineOutPoint, script_sig: ByteArray, witness: Array, sequence: u32 +) -> EngineTransactionInput { let mut compiler = CompilerImpl::new(); let script_sig = compiler.compile(script_sig).unwrap(); - TransactionInput { + EngineTransactionInput { previous_outpoint: outpoint, signature_script: script_sig, witness: witness, @@ -112,18 +123,20 @@ pub fn mock_transaction_input_with( } } -pub fn mock_transaction_input(script_sig: ByteArray) -> TransactionInput { - let outpoint: OutPoint = OutPoint { +pub fn mock_transaction_input(script_sig: ByteArray) -> EngineTransactionInput { + let outpoint: EngineOutPoint = EngineOutPoint { txid: 0xb7994a0db2f373a29227e1d90da883c6ce1cb0dd2d6812e4558041ebbbcfa54b, vout: 0 }; mock_transaction_input_with(outpoint, script_sig, ArrayTrait::new(), 0xffffffff) } -pub fn mock_transaction_output_with(value: i64, script_pubkey: ByteArray) -> TransactionOutput { - TransactionOutput { value: value, publickey_script: script_pubkey } +pub fn mock_transaction_output_with( + value: i64, script_pubkey: ByteArray +) -> EngineTransactionOutput { + EngineTransactionOutput { value: value, publickey_script: script_pubkey } } -pub fn mock_transaction_output() -> TransactionOutput { +pub fn mock_transaction_output() -> EngineTransactionOutput { let output_script_u256: u256 = 0x76a914b3e2819b6262e0b1f19fc7229d75677f347c91ac88ac; let mut output_script: ByteArray = ""; output_script.append_word(output_script_u256.high.into(), 9); @@ -133,11 +146,11 @@ pub fn mock_transaction_output() -> TransactionOutput { pub fn mock_transaction_with( version: i32, - tx_inputs: Array, - tx_outputs: Array, + tx_inputs: Array, + tx_outputs: Array, locktime: u32 -) -> Transaction { - Transaction { +) -> EngineTransaction { + EngineTransaction { version: version, transaction_inputs: tx_inputs, transaction_outputs: tx_outputs, @@ -146,30 +159,30 @@ pub fn mock_transaction_with( } // Mock simple transaction '1d5308ff12cb6fdb670c3af673a6a1317e21fa14fc863d5827f9d704cd5e14dc' -pub fn mock_transaction(script_sig: ByteArray) -> Transaction { - let mut inputs = ArrayTrait::::new(); +pub fn mock_transaction(script_sig: ByteArray) -> EngineTransaction { + let mut inputs = ArrayTrait::::new(); inputs.append(mock_transaction_input(script_sig)); - let mut outputs = ArrayTrait::::new(); + let mut outputs = ArrayTrait::::new(); outputs.append(mock_transaction_output()); return mock_transaction_with(1, inputs, outputs, 0); } // Mock transaction '1d5308ff12cb6fdb670c3af673a6a1317e21fa14fc863d5827f9d704cd5e14dc' // Legacy P2PKH -pub fn mock_transaction_legacy_p2pkh(script_sig: ByteArray) -> Transaction { +pub fn mock_transaction_legacy_p2pkh(script_sig: ByteArray) -> EngineTransaction { mock_transaction(script_sig) } // Mock transaction '949591ad468cef5c41656c0a502d9500671ee421fadb590fbc6373000039b693' // Legacy P2MS -pub fn mock_transaction_legacy_p2ms(script_sig: ByteArray) -> Transaction { - let outpoint: OutPoint = OutPoint { +pub fn mock_transaction_legacy_p2ms(script_sig: ByteArray) -> EngineTransaction { + let outpoint: EngineOutPoint = EngineOutPoint { txid: 0x10a5fee9786a9d2d72c25525e52dd70cbd9035d5152fac83b62d3aa7e2301d58, vout: 0 }; - let mut inputs = ArrayTrait::::new(); + let mut inputs = ArrayTrait::::new(); inputs.append(mock_transaction_input_with(outpoint, script_sig, ArrayTrait::new(), 0xffffffff)); - let mut outputs = ArrayTrait::::new(); + let mut outputs = ArrayTrait::::new(); let output_script_u256: u256 = 0x76a914971802edf585cdbc4e57017d6e5142515c1e502888ac; let mut output_script: ByteArray = ""; output_script.append_word(output_script_u256.high.into(), 9); @@ -179,17 +192,19 @@ pub fn mock_transaction_legacy_p2ms(script_sig: ByteArray) -> Transaction { return mock_transaction_with(1, inputs, outputs, 0); } -pub fn mock_witness_transaction() -> Transaction { - let outpoint_0: OutPoint = OutPoint { +pub fn mock_witness_transaction() -> EngineTransaction { + let outpoint_0: EngineOutPoint = EngineOutPoint { txid: 0xac4994014aa36b7f53375658ef595b3cb2891e1735fe5b441686f5e53338e76a, vout: 1 }; - let transaction_input_0: TransactionInput = TransactionInput { + let transaction_input_0: EngineTransactionInput = EngineTransactionInput { previous_outpoint: outpoint_0, signature_script: "", witness: ArrayTrait::::new(), sequence: 0xffffffff }; - let mut transaction_inputs: Array = ArrayTrait::::new(); + let mut transaction_inputs: Array = ArrayTrait::< + EngineTransactionInput + >::new(); transaction_inputs.append(transaction_input_0); let script_u256: u256 = 0x76a914ce72abfd0e6d9354a660c18f2825eb392f060fdc88ac; let mut script_byte: ByteArray = ""; @@ -197,13 +212,15 @@ pub fn mock_witness_transaction() -> Transaction { script_byte.append_word(script_u256.high.into(), 9); script_byte.append_word(script_u256.low.into(), 16); - let output_0: TransactionOutput = TransactionOutput { + let output_0: EngineTransactionOutput = EngineTransactionOutput { value: 15000, publickey_script: script_byte }; - let mut transaction_outputs: Array = ArrayTrait::::new(); + let mut transaction_outputs: Array = ArrayTrait::< + EngineTransactionOutput + >::new(); transaction_outputs.append(output_0); - Transaction { + EngineTransaction { version: 2, transaction_inputs: transaction_inputs, transaction_outputs: transaction_outputs, @@ -212,21 +229,23 @@ pub fn mock_witness_transaction() -> Transaction { } // Mock transaction with specified 'locktime' and with the 'sequence' field set to locktime -pub fn mock_transaction_legacy_locktime(script_sig: ByteArray, locktime: u32) -> Transaction { - let mut inputs = ArrayTrait::::new(); - let outpoint = OutPoint { txid: 0, vout: 0 }; +pub fn mock_transaction_legacy_locktime(script_sig: ByteArray, locktime: u32) -> EngineTransaction { + let mut inputs = ArrayTrait::::new(); + let outpoint = EngineOutPoint { txid: 0, vout: 0 }; let input = mock_transaction_input_with(outpoint, script_sig, ArrayTrait::new(), 0xfffffffe); inputs.append(input); - let outputs = ArrayTrait::::new(); + let outputs = ArrayTrait::::new(); return mock_transaction_with(1, inputs, outputs, locktime); } // Mock transaction version 2 with the specified 'sequence' -pub fn mock_transaction_legacy_sequence_v2(script_sig: ByteArray, sequence: u32) -> Transaction { - let mut inputs = ArrayTrait::::new(); - let outpoint = OutPoint { txid: 0, vout: 0 }; +pub fn mock_transaction_legacy_sequence_v2( + script_sig: ByteArray, sequence: u32 +) -> EngineTransaction { + let mut inputs = ArrayTrait::::new(); + let outpoint = EngineOutPoint { txid: 0, vout: 0 }; let input = mock_transaction_input_with(outpoint, script_sig, ArrayTrait::new(), sequence); inputs.append(input); - let outputs = ArrayTrait::::new(); + let outputs = ArrayTrait::::new(); return mock_transaction_with(2, inputs, outputs, 0); } diff --git a/packages/engine/src/utxo.cairo b/packages/tests/src/utxo.cairo similarity index 100% rename from packages/engine/src/utxo.cairo rename to packages/tests/src/utxo.cairo diff --git a/packages/engine/src/validate.cairo b/packages/tests/src/validate.cairo similarity index 67% rename from packages/engine/src/validate.cairo rename to packages/tests/src/validate.cairo index b751fd5c..211b67f4 100644 --- a/packages/engine/src/validate.cairo +++ b/packages/tests/src/validate.cairo @@ -1,5 +1,6 @@ -use crate::engine::EngineInternalImpl; -use crate::transaction::Transaction; +use shinigami_engine::engine::EngineImpl; +use shinigami_engine::hash_cache::HashCacheImpl; +use shinigami_engine::transaction::EngineTransaction; use crate::utxo::UTXO; // TODO: Move validate coinbase here @@ -7,7 +8,7 @@ use crate::utxo::UTXO; // TODO: Remove hints? // utxo_hints: Set of existing utxos that are being spent by this transaction pub fn validate_transaction( - tx: Transaction, flags: u32, utxo_hints: Array + tx: @EngineTransaction, flags: u32, utxo_hints: Array ) -> Result<(), felt252> { let input_count = tx.transaction_inputs.len(); if input_count != utxo_hints.len() { @@ -18,9 +19,10 @@ pub fn validate_transaction( let mut err = ''; while i != input_count { let utxo = utxo_hints[i]; + let hash_cache = HashCacheImpl::new(tx); // TODO: Error handling - let mut engine = EngineInternalImpl::new( - utxo.pubkey_script, tx.clone(), i, flags, *utxo.amount + let mut engine = EngineImpl::new( + utxo.pubkey_script, tx, i, flags, *utxo.amount, @hash_cache ) .unwrap(); let res = engine.execute(); diff --git a/packages/utils/src/byte_array.cairo b/packages/utils/src/byte_array.cairo index 28cb9e6e..e8c1de9f 100644 --- a/packages/utils/src/byte_array.cairo +++ b/packages/utils/src/byte_array.cairo @@ -31,7 +31,8 @@ pub fn byte_array_value_at_be(byte_array: @ByteArray, ref offset: usize, len: us let byte_shift = 256; let mut value = 0; let mut i = offset; - while i != offset + len { + let end = offset + len; + while i != end { value = value * byte_shift + byte_array[i].into(); i += 1; }; @@ -59,7 +60,8 @@ pub fn byte_array_value_at_le( pub fn sub_byte_array(byte_array: @ByteArray, ref offset: usize, len: usize) -> ByteArray { let mut sub_byte_array = ""; let mut i = offset; - while i != offset + len { + let end = offset + len; + while i != end { sub_byte_array.append_byte(byte_array[i]); i += 1; }; @@ -116,7 +118,8 @@ pub fn u256_from_byte_array_with_offset(arr: @ByteArray, offset: usize, len: usi pub fn byte_array_to_bool(bytes: @ByteArray) -> bool { let mut i = 0; let mut ret_bool = false; - while i < bytes.len() { + let byte_array_len = bytes.len(); + while i != byte_array_len { if bytes.at(i).unwrap() != 0 { // Can be negative zero if i == bytes.len() - 1 && bytes.at(i).unwrap() == 0x80 { diff --git a/packages/utils/src/hash.cairo b/packages/utils/src/hash.cairo index 68d05853..dea7c008 100644 --- a/packages/utils/src/hash.cairo +++ b/packages/utils/src/hash.cairo @@ -10,6 +10,10 @@ pub fn sha256_byte_array(byte: @ByteArray) -> ByteArray { hash_value } +pub fn double_sha256_bytearray(byte: @ByteArray) -> ByteArray { + return sha256_byte_array(@sha256_byte_array(byte)); +} + pub fn double_sha256(byte: @ByteArray) -> u256 { let msg_hash = compute_sha256_byte_array(byte); let mut res_bytes = ""; diff --git a/scripts/run_bitcoin_transaction.sh b/scripts/run_bitcoin_transaction.sh new file mode 100755 index 00000000..5146eeb8 --- /dev/null +++ b/scripts/run_bitcoin_transaction.sh @@ -0,0 +1,75 @@ +#!/bin/bash +# +# This script fetches and runs a bitcoin transaction using Shinigami Script Engine. + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +BASE_DIR=$SCRIPT_DIR/.. + +TXID=$1 + +RPC_API="https://bitcoin-mainnet.public.blastapi.io" + +# Input needed +# raw_transaction_hex: ByteArray, +# utxo_hints: Array +# pub struct UTXO { +# pub amount: i64, +# pub pubkey_script: ByteArray, +# pub block_height: i32, +# // TODO: flags? +#} + +# Fetch the transaction +RES=$(curl -s -X POST -H "Content-Type: application/json" -d "{\"jsonrpc\":\"1.0\",\"id\":0,\"method\":\"getrawtransaction\",\"params\":[\"$TXID\", true]}" $RPC_API) + +RAW_TX_HEX=$(echo $RES | jq '.result.hex' | tr -d '"') +RAW_TX_HEX="0x$RAW_TX_HEX" +# echo "RAW_TX_HEX: $RAW_TX_HEX" + +RAW_TX_TEXT=$($SCRIPT_DIR/text_to_byte_array.sh $RAW_TX_HEX) +RAW_TX_INPUT=$(sed 's/^\[\(.*\)\]$/\1/' <<< $RAW_TX_TEXT) +# echo "RAW_TX_INPUT: $RAW_TX_INPUT" + +# Fetch the vin's for utxo_hints +VINS=$(echo $RES | jq '.result.vin') +# echo "VINS: $VINS" + +BLOCK_HEIGHT=0 # TODO? +AMOUNT=0 # TODO? +UTXOS="" +for vin in $(echo $VINS | jq -r '.[] | @base64'); do + _jq() { + echo ${vin} | base64 --decode | jq -r ${1} + } + + TXID=$(echo $(_jq '.txid')) + VOUT=$(echo $(_jq '.vout')) + + # Fetch the transaction + RES=$(curl -s -X POST -H "Content-Type: application/json" -d "{\"jsonrpc\":\"1.0\",\"id\":0,\"method\":\"getrawtransaction\",\"params\":[\"$TXID\", true]}" $RPC_API) + + # AMOUNT=$(echo $RES | jq ".result.vout[$VOUT].value") + # echo "AMOUNT: $AMOUNT" + + PUBKEY_SCRIPT=$(echo $RES | jq ".result.vout[$VOUT].scriptPubKey.hex" | tr -d '"') + PUBKEY_SCRIPT="0x$PUBKEY_SCRIPT" + # echo "PUBKEY_SCRIPT: $PUBKEY_SCRIPT" + + PUBKEY_SCRIPT_TEXT=$($SCRIPT_DIR/text_to_byte_array.sh $PUBKEY_SCRIPT) + PUBKEY_SCRIPT_INPUT=$(sed 's/^\[\(.*\)\]$/\1/' <<< $PUBKEY_SCRIPT_TEXT) + # echo "PUBKEY_SCRIPT_INPUT: $PUBKEY_SCRIPT_INPUT" + + # Construct UTXO + UTXO="{\"amount\":$AMOUNT,\"pubkey_script\":\"$PUBKEY_SCRIPT\",\"block_height\":$BLOCK_HEIGHT}" + # echo "UTXO: $UTXO" + + UTXOS="$UTXOS$AMOUNT,$PUBKEY_SCRIPT_INPUT,$BLOCK_HEIGHT," +done +UTXOS=$(sed 's/,$//' <<< $UTXOS) + +JOINED_INPUT="[$RAW_TX_INPUT,[$UTXOS]]" +# echo "JOINED_INPUT: $JOINED_INPUT" + +echo "scarb cairo-run --package shinigami_cmds --function run_raw_transaction \"$JOINED_INPUT\"" +scarb cairo-run --package shinigami_cmds --function run_raw_transaction --no-build $JOINED_INPUT +# TODO: Error checking diff --git a/scripts/run_block_transactions.sh b/scripts/run_block_transactions.sh new file mode 100755 index 00000000..4d2f8072 --- /dev/null +++ b/scripts/run_block_transactions.sh @@ -0,0 +1,55 @@ +#!/bin/bash +# +# This script fetches and runs a bitcoin transaction using Shinigami Script Engine. + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +BASE_DIR=$SCRIPT_DIR/.. + +BLOCK=$1 +echo "Running block $BLOCK" + +OUTPUTS=$BASE_DIR/outputs/block-$BLOCK +mkdir -p $OUTPUTS + +RPC_API="https://bitcoin-mainnet.public.blastapi.io" + +# Fetch blockhash +RES=$(curl -s -X POST -H "Content-Type: application/json" -d "{\"jsonrpc\":\"1.0\",\"id\":0,\"method\":\"getblockhash\", \"params\": [$BLOCK]}" $RPC_API) +BLOCKHASH=$(echo $RES | jq -r '.result') + +# Fetch the block +RES=$(curl -s -X POST -H "Content-Type: application/json" -d "{\"jsonrpc\":\"1.0\",\"id\":0,\"method\":\"getblock\", \"params\": [\"$BLOCKHASH\"]}" $RPC_API) + +# Loop through the transactions +FIRST_IDX=$2 +if [ -z "$FIRST_IDX" ]; then + FIRST_IDX=0 +fi +LAST_IDX=$3 +if [ -z "$LAST_IDX" ]; then + LAST_IDX=$(echo $RES | jq -r ".result.tx | length") +fi +IDX=$FIRST_IDX +while true; do + TXID=$(echo $RES | jq -r ".result.tx[$IDX]") + if [ "$TXID" == "null" ]; then + break + fi + OUTPUT_FILE=$OUTPUTS/tx-$IDX.txt + rm -f $OUTPUT_FILE + touch $OUTPUT_FILE + echo "Running transaction $BLOCK::$IDX - $TXID" >> $OUTPUT_FILE + echo "" >> $OUTPUT_FILE + if [ $IDX -eq 0 ]; then + # TODO + echo "Skipping coinbase transaction" >> $OUTPUT_FILE + IDX=$((IDX+1)) + continue + fi + $SCRIPT_DIR/run_bitcoin_transaction.sh $TXID >> $OUTPUT_FILE + IDX=$((IDX+1)) + if [ $IDX -ge $LAST_IDX ]; then + break + fi +done +echo "Done running block $BLOCK" diff --git a/scripts/run_blocks.sh b/scripts/run_blocks.sh new file mode 100755 index 00000000..6b5c1a5e --- /dev/null +++ b/scripts/run_blocks.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# +# This script runs all transactions in a blocks + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +BASE_DIR=$SCRIPT_DIR/.. + +echo "Building shinigami..." +cd $BASE_DIR && scarb build +echo "Shinigami built successfully!" +echo + +START_BLOCK=$1 +END_BLOCK=$2 +echo "Running blocks $START_BLOCK to $END_BLOCK" + +IDX=$START_BLOCK +while true; do + $SCRIPT_DIR/run_block_transactions.sh $IDX + IDX=$((IDX+1)) + if [ $IDX -ge $END_BLOCK ]; then + break + fi +done +echo "Done running blocks" diff --git a/tests/text_to_byte_array.sh b/scripts/text_to_byte_array.sh similarity index 100% rename from tests/text_to_byte_array.sh rename to scripts/text_to_byte_array.sh diff --git a/tests/run-core-tests.sh b/tests/run-core-tests.sh index 5a7faabe..4f233dc0 100755 --- a/tests/run-core-tests.sh +++ b/tests/run-core-tests.sh @@ -3,8 +3,10 @@ # Runs the tests from bitcoin-core # https://github.com/bitcoin/bitcoin/blob/master/src/test/data/ -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -BASE_DIR=$SCRIPT_DIR/.. +TEST_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +BASE_DIR=$TEST_DIR/.. +SCRIPT_DIR=$BASE_DIR/scripts +TEXT_TO_BYTE_ARRAY_SCRIPT="$BASE_DIR/scripts/text_to_byte_array.sh" echo "Building shinigami..." cd $BASE_DIR && scarb build @@ -22,7 +24,14 @@ fi # Run the script_tests.json tests # TODO: Pull from bitcoin-core repo? -SCRIPT_TESTS_JSON=$SCRIPT_DIR/script_tests.json +SCRIPT_TESTS_JSON=$TEST_DIR/script_tests.json +PASSING_TESTS_JSON=$TEST_DIR/script_tests_passing.json +FAILED_TESTS_JSON=$TEST_DIR/script_tests_failing.json + +rm -f $PASSING_TESTS_JSON +rm -f $FAILED_TESTS_JSON +touch $PASSING_TESTS_JSON +touch $FAILED_TESTS_JSON echo "Running script_tests.json tests..." echo @@ -74,9 +83,9 @@ jq -c '.[]' $SCRIPT_TESTS_JSON | { # echo " " # Run the test - ENCODED_SCRIPT_SIG=$($SCRIPT_DIR/text_to_byte_array.sh "$scriptSig") # Encoded like [["123", "456", ...], "789", 3] - ENCODED_SCRIPT_PUB_KEY=$($SCRIPT_DIR/text_to_byte_array.sh "$scriptPubKey") # Encoded like [["123", "456", ...], "789", 3] - ENCODED_FLAGS=$($SCRIPT_DIR/text_to_byte_array.sh "$flags") # Encoded like [["123", "456", ...], "789", 3] + ENCODED_SCRIPT_SIG=$($TEXT_TO_BYTE_ARRAY_SCRIPT "$scriptSig") # Encoded like [["123", "456", ...], "789", 3] + ENCODED_SCRIPT_PUB_KEY=$($TEXT_TO_BYTE_ARRAY_SCRIPT "$scriptPubKey") # Encoded like [["123", "456", ...], "789", 3] + ENCODED_FLAGS=$($TEXT_TO_BYTE_ARRAY_SCRIPT "$flags") # Encoded like [["123", "456", ...], "789", 3] # Remove the outer brackets and join the arrays TRIMMED_SCRIPT_SIG=$(sed 's/^\[\(.*\)\]$/\1/' <<< $ENCODED_SCRIPT_SIG) TRIMMED_SCRIPT_PUB_KEY=$(sed 's/^\[\(.*\)\]$/\1/' <<< $ENCODED_SCRIPT_PUB_KEY) @@ -86,7 +95,7 @@ jq -c '.[]' $SCRIPT_TESTS_JSON | { if [ $has_witness == "true" ]; then #TODO: Value echo " ScriptSig: '$scriptSig' -- ScriptPubKey: '$scriptPubKey' -- Flags: '$flags' -- Expected: $expected_scripterror -- Witness: $witness" - ENCODED_WITNESS=$($SCRIPT_DIR/text_to_byte_array.sh "$witness") + ENCODED_WITNESS=$($TEXT_TO_BYTE_ARRAY_SCRIPT "$witness") TRIMMED_WITNESS=$(sed 's/^\[\(.*\)\]$/\1/' <<< $ENCODED_WITNESS) JOINED_INPUT="[$TRIMMED_SCRIPT_SIG,$TRIMMED_SCRIPT_PUB_KEY,$TRIMMED_FLAGS,$TRIMMED_WITNESS]" RESULT=$(cd $BASE_DIR && scarb cairo-run --package shinigami_cmds --function main_with_witness --no-build $JOINED_INPUT) @@ -134,7 +143,16 @@ jq -c '.[]' $SCRIPT_TESTS_JSON | { SCRIPT_SIZE="Execution failed: Engine::new: script too large" CLEAN_STACK="Execution failed: Non-clean stack after execute" MINIMAL_DATA="Execution failed: Opcode represents non-minimal" + MINIMAL_IF="Execution failed: If conditional must be 0 or 1" + SIG_DER="Execution failed: Signature DER error" INVALID_WITNESS="Execution failed: Invalid witness program" + WITNESS_PROGRAM_MISMATCH="Execution failed: Witness program mismatch" + WITNESS_UNEXPECTED="Execution failed: Unexpected witness data" + WITNESS_MALLEATED="Execution failed: Witness program with sig script" + WITNESS_PROGRAM_WRONG_LENGTH="Execution failed: Witness program wrong length" + WITNESS_PROGRAM_EMPTY="Execution failed: Empty witness program" + WITNESS_MALLEATED_P2SH="Execution failed: Signature script for p2sh wit" + WITNESS_PUBKEYTYPE="Execution failed: Non-compressed key post-segwit" if echo "$RESULT" | grep -q "$EVAL_FALSE_RES"; then SCRIPT_RESULT="EVAL_FALSE" elif echo "$RESULT" | grep -q "$EMPTY_STACK_RES"; then @@ -201,6 +219,26 @@ jq -c '.[]' $SCRIPT_TESTS_JSON | { SCRIPT_RESULT="CLEANSTACK" elif echo "$RESULT" | grep -q "$MINIMAL_DATA"; then SCRIPT_RESULT="MINIMALDATA" + elif echo "$RESULT" | grep -q "$MINIMAL_IF"; then + SCRIPT_RESULT="MINIMALIF" + elif echo "$RESULT" | grep -q "$INVALID_WITNESS"; then + SCRIPT_RESULT="INVALID_WITNESS" + elif echo "$RESULT" | grep -q "$WITNESS_PROGRAM_MISMATCH"; then + SCRIPT_RESULT="WITNESS_PROGRAM_MISMATCH" + elif echo "$RESULT" | grep -q "$WITNESS_UNEXPECTED"; then + SCRIPT_RESULT="WITNESS_UNEXPECTED" + elif echo "$RESULT" | grep -q "$WITNESS_MALLEATED"; then + SCRIPT_RESULT="WITNESS_MALLEATED" + elif echo "$RESULT" | grep -q "$WITNESS_PROGRAM_WRONG_LENGTH"; then + SCRIPT_RESULT="WITNESS_PROGRAM_WRONG_LENGTH" + elif echo "$RESULT" | grep -q "$WITNESS_PROGRAM_EMPTY"; then + SCRIPT_RESULT="WITNESS_PROGRAM_WITNESS_EMPTY" + elif echo "$RESULT" | grep -q "$WITNESS_MALLEATED_P2SH"; then + SCRIPT_RESULT="WITNESS_MALLEATED_P2SH" + elif echo "$RESULT" | grep -q "$WITNESS_PUBKEYTYPE"; then + SCRIPT_RESULT="WITNESS_PUBKEYTYPE" + elif echo "$RESULT" | grep -q "$SIG_DER"; then + SCRIPT_RESULT="SIG_DER" else SCRIPT_RESULT="FAIL" fi @@ -219,18 +257,27 @@ jq -c '.[]' $SCRIPT_TESTS_JSON | { if [ "$SCRIPT_RESULT" == "$expected_scripterror" ]; then echo -e " \033[0;32mPASS\033[0m" PASSED=$((PASSED+1)) + echo $line, >> $PASSING_TESTS_JSON elif [[ "$SCRIPT_RESULT" == "MINIMALDATA" && "$expected_scripterror" == "UNKNOWN_ERROR" ]]; then echo -e " \033[0;32mPASS\033[0m" PASSED=$((PASSED+1)) + echo $line, >> $PASSING_TESTS_JSON elif [[ "$SCRIPT_RESULT" == "INVALID_STACK_OPERATION" && "$expected_scripterror" == "UNBALANCED_CONDITIONAL" ]]; then # handle cases like 'IF 0 ENDIF' ie no value on stack for if echo -e " \033[0;32mPASS\033[0m" PASSED=$((PASSED+1)) + echo $line, >> $PASSING_TESTS_JSON else echo -e " \033[0;31mFAIL\033[0m" FAILED=$((FAILED+1)) - echo "scarb cairo-run --package shinigami_cmds '$JOINED_INPUT'" + # Print the command that failed + if [ $has_witness == "true" ]; then + echo "scarb cairo-run --package shinigami_cmds --function main_with_witness '$JOINED_INPUT'" + else + echo "scarb cairo-run --package shinigami_cmds '$JOINED_INPUT'" + fi echo "$RESULT" + echo $line, >> $FAILED_TESTS_JSON fi echo @@ -248,7 +295,7 @@ jq -c '.[]' $SCRIPT_TESTS_JSON | { # TODO: Pull from bitcoin-core repo? # Run the tx_valid.json tests exit 0 # TODO -TX_VALID_JSON=$SCRIPT_DIR/tx_valid.json +TX_VALID_JSON=$TEST_DIR/tx_valid.json jq -c '.[]' $TX_VALID_JSON | while read line; do # If line contains on string, ie ["XXX"], skip it diff --git a/tests/run-failing-core-tests.sh b/tests/run-failing-core-tests.sh index 26eeb054..a3e44303 100755 --- a/tests/run-failing-core-tests.sh +++ b/tests/run-failing-core-tests.sh @@ -1,10 +1,11 @@ #!/bin/bash # -# Runs the tests from bitcoin-core +# Runs the failing tests from bitcoin-core # https://github.com/bitcoin/bitcoin/blob/master/src/test/data/ -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -BASE_DIR=$SCRIPT_DIR/.. +TEST_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +BASE_DIR=$TEST_DIR/.. +SCRIPT_DIR=$BASE_DIR/scripts echo "Building shinigami..." cd $BASE_DIR && scarb build @@ -22,7 +23,7 @@ fi # Run the script_tests.json tests # TODO: Pull from bitcoin-core repo? -SCRIPT_TESTS_JSON=$SCRIPT_DIR/script_tests_failing.json +SCRIPT_TESTS_JSON=$TEST_DIR/script_tests_failing.json echo "Running script_tests.json tests..." echo @@ -135,6 +136,7 @@ jq -c '.[]' $SCRIPT_TESTS_JSON | { CLEAN_STACK="Execution failed: Non-clean stack after execute" MINIMAL_DATA="Execution failed: Opcode represents non-minimal" INVALID_WITNESS="Execution failed: Invalid witness program" + SIG_DER="Execution failed: Signature DER error" if echo "$RESULT" | grep -q "$EVAL_FALSE_RES"; then SCRIPT_RESULT="EVAL_FALSE" elif echo "$RESULT" | grep -q "$EMPTY_STACK_RES"; then @@ -201,6 +203,8 @@ jq -c '.[]' $SCRIPT_TESTS_JSON | { SCRIPT_RESULT="CLEANSTACK" elif echo "$RESULT" | grep -q "$MINIMAL_DATA"; then SCRIPT_RESULT="MINIMALDATA" + elif echo "$RESULT" | grep -q "$SIG_DER"; then + SCRIPT_RESULT="SIG_DER" else SCRIPT_RESULT="FAIL" fi @@ -245,39 +249,3 @@ jq -c '.[]' $SCRIPT_TESTS_JSON | { echo "Script tests complete!" echo "Passed: $PASSED Failed: $FAILED Total: $((PASSED+FAILED))" } - - -# TODO: Pull from bitcoin-core repo? -# Run the tx_valid.json tests -exit 0 # TODO -TX_VALID_JSON=$SCRIPT_DIR/tx_valid.json - -jq -c '.[]' $TX_VALID_JSON | while read line; do - # If line contains on string, ie ["XXX"], skip it - if [[ $line != *\"*\"*\,\"*\"* ]]; then - continue - fi - # Otherwise, line encoded like [[[prevout hash, prevout index, prevout scriptPubKey, amount?], [input 2], ...], serializedTransaction, excluded verifyFlags] - # Extract line data - prevouts=$(echo $line | jq -r '.[0]') # TODO: Use prevouts - tx=$(echo $line | jq -r '.[1]') - flags=$(echo $line | jq -r '.[2]') # TODO: Use flags - - # Extract prevouts - prevout_hashs=$(jq -r '.[] | .[0]' <<< $prevouts) - prevout_indexes=$(jq -r '.[] | .[1]' <<< $prevouts) - prevout_scripts=$(jq -r '.[] | .[2]' <<< $prevouts) - prevout_amounts=$(jq -r '.[] | .[3]' <<< $prevouts) - - echo "Running test with " - echo " Tx: $tx" - echo " Prevout Hashs: $prevout_hashs" - echo " Prevout Indexes: $prevout_indexes" - echo " Prevout Scripts: $prevout_scripts" - echo " Prevout Amounts: $prevout_amounts" - echo " Flags: $flags" - echo " " - echo "-----------------------------------------------------------------" - echo " " - -done diff --git a/tests/run-passing-core-tests.sh b/tests/run-passing-core-tests.sh new file mode 100755 index 00000000..870d639d --- /dev/null +++ b/tests/run-passing-core-tests.sh @@ -0,0 +1,282 @@ +#!/bin/bash +# +# Runs the passing tests from bitcoin-core +# https://github.com/bitcoin/bitcoin/blob/master/src/test/data/ + +MAX_PARALLEL=3 + +commands=() +pids=() +exit_codes=() + +TEST_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +BASE_DIR=$TEST_DIR/.. +SCRIPT_DIR=$BASE_DIR/scripts +TEXT_TO_BYTE_ARRAY_SCRIPT="$BASE_DIR/scripts/text_to_byte_array.sh" + +echo "Building shinigami..." +cd $BASE_DIR && scarb build +echo "Shinigami built successfully!" +echo + +START=0 +if [ -n "$1" ]; then + START=$1 +fi +END=1207 +if [ -n "$2" ]; then + END=$2 +fi + +# Run the script_tests.json tests +# TODO: Pull from bitcoin-core repo? +SCRIPT_TESTS_JSON=$TEST_DIR/script_tests_passing.json + +echo "Running script_tests.json tests..." +echo +SCRIPT_IDX=0 +jq -c '.[]' $SCRIPT_TESTS_JSON | { + while read line; do + # If line contains one string, ie ["XXX"], skip it + if [[ $line != *\"*\"*\,\"*\"* ]]; then + continue + fi + if [ $SCRIPT_IDX -lt $START ]; then + SCRIPT_IDX=$((SCRIPT_IDX+1)) + continue + fi + + has_witness="false" + # Otherwise, line encoded like [[wit..., amount]?, scriptSig, scriptPubKey, flags, expected_scripterror, ... comments] + # Extract line data + # witness_amount=$(echo $line | jq -r '.[0]') # TODO: Use witness_amount + # Check if first element is an array or string + first_element=$(echo $line | jq -c '.[0]') + # Check if first element contains a comma + if [[ $first_element == *","* ]]; then + witness=$(echo $line | jq -c '.[0][:-1]') + # Add 0x to each witness element and join them with a comma + witness=$(echo $witness | jq -r 'map("0x" + .) | join(",")') + witness_amount=$(echo $line | jq -r '.[0][-1]') + scriptSig=$(echo $line | jq -r '.[1]') + scriptPubKey=$(echo $line | jq -r '.[2]') + flags=$(echo $line | jq -r '.[3]') + expected_scripterror=$(echo $line | jq -r '.[4]') + has_witness="true" + #comments=$(echo $line | jq -r '.[5]') + else + scriptSig=$(echo $line | jq -r '.[0]') + scriptPubKey=$(echo $line | jq -r '.[1]') + flags=$(echo $line | jq -r '.[2]') + expected_scripterror=$(echo $line | jq -r '.[3]') + #comments=$(echo $line | jq -r '.[4]') + fi + + # echo " Witness Amount: $witness_amount" + # echo " Flags: $flags" + # echo " Comments: $comments" + # echo " " + # echo "-----------------------------------------------------------------" + # echo " " + + # Run the test + ENCODED_SCRIPT_SIG=$($TEXT_TO_BYTE_ARRAY_SCRIPT "$scriptSig") # Encoded like [["123", "456", ...], "789", 3] + ENCODED_SCRIPT_PUB_KEY=$($TEXT_TO_BYTE_ARRAY_SCRIPT "$scriptPubKey") # Encoded like [["123", "456", ...], "789", 3] + ENCODED_FLAGS=$($TEXT_TO_BYTE_ARRAY_SCRIPT "$flags") # Encoded like [["123", "456", ...], "789", 3] + # Remove the outer brackets and join the arrays + TRIMMED_SCRIPT_SIG=$(sed 's/^\[\(.*\)\]$/\1/' <<< $ENCODED_SCRIPT_SIG) + TRIMMED_SCRIPT_PUB_KEY=$(sed 's/^\[\(.*\)\]$/\1/' <<< $ENCODED_SCRIPT_PUB_KEY) + TRIMMED_FLAGS=$(sed 's/^\[\(.*\)\]$/\1/' <<< $ENCODED_FLAGS) + + RESULT="" + if [ $has_witness == "true" ]; then + #TODO: Value + ENCODED_WITNESS=$($TEXT_TO_BYTE_ARRAY_SCRIPT "$witness") + TRIMMED_WITNESS=$(sed 's/^\[\(.*\)\]$/\1/' <<< $ENCODED_WITNESS) + JOINED_INPUT="[$TRIMMED_SCRIPT_SIG,$TRIMMED_SCRIPT_PUB_KEY,$TRIMMED_FLAGS,$TRIMMED_WITNESS]" + commands+=("cd $BASE_DIR && scarb cairo-run --package shinigami_cmds --function main_with_witness --no-build $JOINED_INPUT") + else + JOINED_INPUT="[$TRIMMED_SCRIPT_SIG,$TRIMMED_SCRIPT_PUB_KEY,$TRIMMED_FLAGS]" + commands+=("cd $BASE_DIR && scarb cairo-run --package shinigami_cmds --no-build $JOINED_INPUT") + fi + done + + execute_test() { + RESULT=$@ + SUCCESS_RES="Run completed successfully, returning \[1\]" + FAILURE_RES="Run completed successfully, returning \[0\]" + SCRIPT_RESULT="" + if echo "$RESULT" | grep -q "$SUCCESS_RES"; then + SCRIPT_RESULT="OK" + elif echo "$RESULT" | grep -q "$FAILURE_RES"; then + EVAL_FALSE_RES="Execution failed: Script failed after execute" + EMPTY_STACK_RES="Execution failed: Stack empty after execute" + UNBALANCED_CONDITIONAL="Execution failed: Unbalanced conditional" + RESERVED_OP_RES="Execution failed: Opcode reserved" + UNIMPLEMENTED_OP_RES="Execution failed: Opcode not implemented" + INVALID_ELSE_RES="Execution failed: opcode_else: no matching if" + INVALID_ENDIF_RES="Execution failed: opcode_endif: no matching if" + RETURN_EARLY_RES="Execution failed: opcode_return: returned early" + STACK_UNDERFLOW_RES="Execution failed: Stack underflow" + STACK_OUT_OF_RANGE_RES="Execution failed: Stack out of range" + DISABLED_OP_RES="Execution failed: Opcode is disabled" + VERIFY_FAILED_RES="Execution failed: Verify failed" + SCRIPTNUM_OVERFLOW_RES="Execution failed: Scriptnum out of range" + INVALID_SCRIPT_DATA="Execution failed: Invalid script data" + STACK_OVERFLOW="Execution failed: Stack overflow" + INVALID_PUBKEY_COUNT="Execution failed: check multisig: num pk < 0" + INVALID_SIG_COUNT="Execution failed: check multisig: num sigs < 0" + NONZERO_NULLFAIL="Execution failed: Sig non-zero on failed checksig" + SIG_NULLFAIL="Execution failed: OP_CHECKMULTISIG invalid dummy" + DISCOURAGE_UPGRADABLE_NOPS="Execution failed: Upgradable NOPs are discouraged" + PUSH_SIZE="Execution failed: Push value size limit exceeded" + OP_COUNT="Execution failed: Too many operations" + PUBKEY_COUNT="Execution failed: check multisig: num pk > max" + SIG_COUNT="Execution failed: check multisig: num sigs > pk" + SIG_PUSHONLY="Execution failed: Engine::new: not pushonly" + SIG_PUSHONLY2="Execution failed: Engine::new: p2sh not pushonly" + PUBKEYTYPE="Execution failed: unsupported public key type" + INVALID_SIG_FMT="Execution failed: invalid sig fmt: too short" + INVALID_HASH_TYPE="Execution failed: invalid hash type" + INVALID_LOCKTIME="Execution failed: Unsatisfied locktime" + SCRIPT_SIZE="Execution failed: Engine::new: script too large" + CLEAN_STACK="Execution failed: Non-clean stack after execute" + MINIMAL_DATA="Execution failed: Opcode represents non-minimal" + INVALID_WITNESS="Execution failed: Invalid witness program" + SIG_DER="Execution failed: Signature DER error" + if echo "$RESULT" | grep -q "$EVAL_FALSE_RES"; then + SCRIPT_RESULT="EVAL_FALSE" + elif echo "$RESULT" | grep -q "$EMPTY_STACK_RES"; then + SCRIPT_RESULT="EVAL_FALSE" + elif echo "$RESULT" | grep -q "$UNBALANCED_CONDITIONAL"; then + SCRIPT_RESULT="UNBALANCED_CONDITIONAL" + elif echo "$RESULT" | grep -q "$RESERVED_OP_RES"; then + SCRIPT_RESULT="BAD_OPCODE" + elif echo "$RESULT" | grep -q "$UNIMPLEMENTED_OP_RES"; then + SCRIPT_RESULT="BAD_OPCODE" + elif echo "$RESULT" | grep -q "$INVALID_SCRIPT_DATA"; then + SCRIPT_RESULT="BAD_OPCODE" + elif echo "$RESULT" | grep -q "$INVALID_ELSE_RES"; then + SCRIPT_RESULT="UNBALANCED_CONDITIONAL" + elif echo "$RESULT" | grep -q "$INVALID_ENDIF_RES"; then + SCRIPT_RESULT="UNBALANCED_CONDITIONAL" + elif echo "$RESULT" | grep -q "$RETURN_EARLY_RES"; then + SCRIPT_RESULT="OP_RETURN" + elif echo "$RESULT" | grep -q "$STACK_UNDERFLOW_RES"; then + SCRIPT_RESULT="INVALID_STACK_OPERATION" + elif echo "$RESULT" | grep -q "$STACK_OUT_OF_RANGE_RES"; then + SCRIPT_RESULT="INVALID_STACK_OPERATION" + elif echo "$RESULT" | grep -q "$STACK_OVERFLOW"; then + SCRIPT_RESULT="STACK_SIZE" + elif echo "$RESULT" | grep -q "$DISABLED_OP_RES"; then + SCRIPT_RESULT="DISABLED_OPCODE" + elif echo "$RESULT" | grep -q "$VERIFY_FAILED_RES"; then + SCRIPT_RESULT="VERIFY" + elif echo "$RESULT" | grep -q "$SCRIPTNUM_OVERFLOW_RES"; then + SCRIPT_RESULT="UNKNOWN_ERROR" + elif echo "$RESULT" | grep -q "$INVALID_PUBKEY_COUNT"; then + SCRIPT_RESULT="PUBKEY_COUNT" + elif echo "$RESULT" | grep -q "$PUBKEY_COUNT"; then + SCRIPT_RESULT="PUBKEY_COUNT" + elif echo "$RESULT" | grep -q "$SIG_COUNT"; then + SCRIPT_RESULT="SIG_COUNT" + elif echo "$RESULT" | grep -q "$SIG_PUSHONLY"; then + SCRIPT_RESULT="SIG_PUSHONLY" + elif echo "$RESULT" | grep -q "$SIG_PUSHONLY2"; then + SCRIPT_RESULT="SIG_PUSHONLY" + elif echo "$RESULT" | grep -q "$PUBKEYTYPE"; then + SCRIPT_RESULT="PUBKEYTYPE" + elif echo "$RESULT" | grep -q "$INVALID_SIG_COUNT"; then + SCRIPT_RESULT="SIG_COUNT" + elif echo "$RESULT" | grep -q "$INVALID_SIG_FMT"; then + SCRIPT_RESULT="SIG_DER" + elif echo "$RESULT" | grep -q "$INVALID_HASH_TYPE"; then + SCRIPT_RESULT="SIG_DER" + elif echo "$RESULT" | grep -q "$NONZERO_NULLFAIL"; then + SCRIPT_RESULT="NULLFAIL" + elif echo "$RESULT" | grep -q "$SIG_NULLFAIL"; then + SCRIPT_RESULT="SIG_NULLDUMMY" + elif echo "$RESULT" | grep -q "$DISCOURAGE_UPGRADABLE_NOPS"; then + SCRIPT_RESULT="DISCOURAGE_UPGRADABLE_NOPS" + elif echo "$RESULT" | grep -q "$PUSH_SIZE"; then + SCRIPT_RESULT="PUSH_SIZE" + elif echo "$RESULT" | grep -q "$OP_COUNT"; then + SCRIPT_RESULT="OP_COUNT" + elif echo "$RESULT" | grep -q "$INVALID_LOCKTIME"; then + SCRIPT_RESULT="NEGATIVE_LOCKTIME" + elif echo "$RESULT" | grep -q "$SCRIPT_SIZE"; then + SCRIPT_RESULT="SCRIPT_SIZE" + elif echo "$RESULT" | grep -q "$CLEAN_STACK"; then + SCRIPT_RESULT="CLEANSTACK" + elif echo "$RESULT" | grep -q "$MINIMAL_DATA"; then + SCRIPT_RESULT="MINIMALDATA" + elif echo "$RESULT" | grep -q "$SIG_DER"; then + SCRIPT_RESULT="SIG_DER" + else + SCRIPT_RESULT="FAIL" + fi + if [ $expected_scripterror == "EQUALVERIFY" ]; then + # TODO: This is a hack to make the test pass for now + expected_scripterror="VERIFY" + elif [ $expected_scripterror == "INVALID_ALTSTACK_OPERATION" ]; then + # TODO: This is a hack to make the test pass for now + expected_scripterror="INVALID_STACK_OPERATION" + fi + else + SCRIPT_RESULT="PANIC" + fi + + # echo if result is expected w/ color + if [ "$SCRIPT_RESULT" == "$expected_scripterror" ]; then + return 0 + elif [[ "$SCRIPT_RESULT" == "MINIMALDATA" && "$expected_scripterror" == "UNKNOWN_ERROR" ]]; then + return 0 + elif [[ "$SCRIPT_RESULT" == "INVALID_STACK_OPERATION" && "$expected_scripterror" == "UNBALANCED_CONDITIONAL" ]]; then + # handle cases like 'IF 0 ENDIF' ie no value on stack for if + return 0 + else + echo "Failed test: $RESULT" + return 1 + fi + } + + run_command() { + RESULT=$(eval "$@") + execute_test $RESULT + return $? + } + + for cmd in "${commands[@]}"; do + while [ ${#pids[@]} -ge $MAX_PARALLEL ]; do + for pid in ${pids[@]}; do + if wait $pid; then + exit_codes+=($?) + pids=(${pids[@]/$pid}) + fi + done + done + run_command $cmd & + pids+=($!) + done + + for pid in ${pids[@]}; do + if wait $pid; then + exit_codes+=($?) + fi + done + + for code in ${exit_codes[@]}; do + if [ $code -ne 0 ]; then + exit $code + fi + done + + echo "Commands ran: ${#commands[@]}" + echo "Results: ${#exit_codes[@]}" + if [ ${#commands[@]} -ne ${#exit_codes[@]} ]; then + echo + echo "Some tests failed!" + exit 1 + fi + echo "All tests passed!" +} diff --git a/tests/script_tests_failing.json b/tests/script_tests_failing.json index 8e85e82c..4cd223ed 100644 --- a/tests/script_tests_failing.json +++ b/tests/script_tests_failing.json @@ -1,96 +1,17 @@ -[ -["0x01 0x00","1","MINIMALDATA","OK"], -["0x27 0x3024021077777777777777777777777777777777020a7777777777777777777777777777777701","0 CHECKSIG NOT","","OK","S with invalid S length is correctly encoded"], -["0x27 0x302402107777777777777777777777777777777702108777777777777777777777777777777701","0 CHECKSIG NOT","","OK","Negative S is correctly encoded"], -["1 0x01 0xb9","HASH160 0x14 0x15727299b05b45fdaf9ac9ecf7565cfe27c3e567 EQUAL","P2SH,DISCOURAGE_UPGRADABLE_NOPS","DISCOURAGE_UPGRADABLE_NOPS","Discouraged NOP10 in redeemScript"], ["","'dummy' 'sig1' 1 'pk1' 1 CHECKMULTISIG IF 1 ENDIF","","EVAL_FALSE","CHECKMULTISIG must push false to stack when signature is invalid when NOT in strict enc mode"], -["0 0x01 0x50","HASH160 0x14 0xece424a6bb6ddf4db592c0faed60685047a361b1 EQUAL","P2SH,STRICTENC","BAD_OPCODE","OP_RESERVED in P2SH should fail"], -["0 0x01 VER","HASH160 0x14 0x0f4d7845db968f2a81b530b6f3c1d6246d4c7e01 EQUAL","P2SH,STRICTENC","BAD_OPCODE","OP_VER in P2SH should fail"], -["0x4a 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","0 CHECKSIG NOT","DERSIG","SIG_DER","Overly long signature is incorrectly encoded for DERSIG"], -["0x25 0x30220220000000000000000000000000000000000000000000000000000000000000000000","0 CHECKSIG NOT","DERSIG","SIG_DER","Missing S is incorrectly encoded for DERSIG"], -["0x27 0x3024021077777777777777777777777777777777020a7777777777777777777777777777777701","0 CHECKSIG NOT","DERSIG","SIG_DER","S with invalid S length is incorrectly encoded for DERSIG"], -["0x27 0x302403107777777777777777777777777777777702107777777777777777777777777777777701","0 CHECKSIG NOT","DERSIG","SIG_DER","Non-integer R is incorrectly encoded for DERSIG"], -["0x27 0x302402107777777777777777777777777777777703107777777777777777777777777777777701","0 CHECKSIG NOT","DERSIG","SIG_DER","Non-integer S is incorrectly encoded for DERSIG"], -["0x17 0x3014020002107777777777777777777777777777777701","0 CHECKSIG NOT","DERSIG","SIG_DER","Zero-length R is incorrectly encoded for DERSIG"], -["0x17 0x3014021077777777777777777777777777777777020001","0 CHECKSIG NOT","DERSIG","SIG_DER","Zero-length S is incorrectly encoded for DERSIG"], -["0x27 0x302402107777777777777777777777777777777702108777777777777777777777777777777701","0 CHECKSIG NOT","DERSIG","SIG_DER","Negative S is incorrectly encoded for DERSIG"], -[["00",0E-8],"","0 0x206e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d","P2SH,WITNESS","EVAL_FALSE","Invalid witness script"], -[["51",0E-8],"","0 0x206e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d","P2SH,WITNESS","WITNESS_PROGRAM_MISMATCH","Witness script hash mismatch"], -[["51",0E-8],"","-1 0x021234","P2SH,WITNESS","WITNESS_UNEXPECTED","OP_1NEGATE does not introduce a witness program"], -[["51",0E-8],"00","1 0x021234","P2SH,WITNESS","WITNESS_MALLEATED","OP_1 does introduce a witness program"], -[["51",0E-8],"00","16 0x021234","P2SH,WITNESS","WITNESS_MALLEATED","OP_16 does introduce a witness program"], -[["51",0E-8],"","NOP 0x021234","P2SH,WITNESS","WITNESS_UNEXPECTED","NOP does not introduce a witness program"], -["0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001","0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG","","OK","P2PK"], -["0x47 0x304402206e05a6fe23c59196ffe176c9ddc31e73a9885638f9d1328d47c0c703863b8876022076feb53811aa5b04e0e79f938eb19906cc5e67548bc555a8e8b8b0fc603d840c01 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508","DUP HASH160 0x14 0x1018853670f9f3b0582c5b9ee8ce93764ac32b93 EQUALVERIFY CHECKSIG","","OK","P2PKH"], -["0x47 0x304402204710a85181663b32d25c70ec2bbd14adff5ddfff6cb50d09e155ef5f541fc86c0220056b0cc949be9386ecc5f6c2ac0493269031dbb185781db90171b54ac127790281","0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG","","OK","P2PK anyonecanpay"], -["0x47 0x304402204e2eb034be7b089534ac9e798cf6a2c79f38bcb34d1b179efd6f2de0841735db022071461beb056b5a7be1819da6a3e3ce3662831ecc298419ca101eb6887b5dd6a401 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac","HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL","P2SH","EQUALVERIFY","P2SH(P2PKH), bad sig"], -["0 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901","3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG","","OK","3-of-3"], -["0 0x47 0x304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf8001 0 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae","HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL","P2SH","EVAL_FALSE","P2SH(2-of-3), 1 sig"], -["0x47 0x304402200060558477337b9022e70534f1fea71a318caf836812465a2509931c5e7c4987022078ec32bd50ac9e03a349ba953dfd9fe1c8d2dd8bdb1d38ddca844d3d5c78c11801","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","","OK","P2PK with too much R padding but no DERSIG"], -["0x47 0x304402200060558477337b9022e70534f1fea71a318caf836812465a2509931c5e7c4987022078ec32bd50ac9e03a349ba953dfd9fe1c8d2dd8bdb1d38ddca844d3d5c78c11801","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","DERSIG","SIG_DER","P2PK with too much R padding"], -["0x48 0x304502202de8c03fc525285c9c535631019a5f2af7c6454fa9eb392a3756a4917c420edd02210046130bf2baf7cfc065067c8b9e33a066d9c15edcea9feb0ca2d233e3597925b401","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","","OK","P2PK with too much S padding but no DERSIG"], -["0x48 0x304502202de8c03fc525285c9c535631019a5f2af7c6454fa9eb392a3756a4917c420edd02210046130bf2baf7cfc065067c8b9e33a066d9c15edcea9feb0ca2d233e3597925b401","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","DERSIG","SIG_DER","P2PK with too much S padding"], -["0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","","OK","P2PK with too little R padding but no DERSIG"], -["0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","DERSIG","SIG_DER","P2PK with too little R padding"], -["0x47 0x30440220005ece1335e7f757a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601","0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT","DERSIG","SIG_DER","P2PK NOT with bad sig with too much R padding"], -["0x47 0x30440220005ece1335e7f657a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601","0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT","","EVAL_FALSE","P2PK NOT with too much R padding but no DERSIG"], -["0x47 0x30440220005ece1335e7f657a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601","0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT","DERSIG","SIG_DER","P2PK NOT with too much R padding"], -["0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","","OK","BIP66 example 1, without DERSIG"], -["0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","DERSIG","SIG_DER","BIP66 example 1, with DERSIG"], -["0x47 0x304402208e43c0b91f7c1e5bc58e41c8185f8a6086e111b0090187968a86f2822462d3c902200a58f4076b1133b18ff1dc83ee51676e44c60cc608d9534e0df5ace0424fc0be01","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT","","EVAL_FALSE","BIP66 example 2, without DERSIG"], -["0x47 0x304402208e43c0b91f7c1e5bc58e41c8185f8a6086e111b0090187968a86f2822462d3c902200a58f4076b1133b18ff1dc83ee51676e44c60cc608d9534e0df5ace0424fc0be01","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT","DERSIG","SIG_DER","BIP66 example 2, with DERSIG"], -["1","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","DERSIG","SIG_DER","BIP66 example 5, with DERSIG"], -["1","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT","DERSIG","SIG_DER","BIP66 example 6, with DERSIG"], -["0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0x47 0x3044022027c2714269ca5aeecc4d70edc88ba5ee0e3da4986e9216028f489ab4f1b8efce022022bd545b4951215267e4c5ceabd4c5350331b2e4a0b6494c56f361fa5a57a1a201","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG","","OK","BIP66 example 7, without DERSIG"], -["0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0x47 0x3044022027c2714269ca5aeecc4d70edc88ba5ee0e3da4986e9216028f489ab4f1b8efce022022bd545b4951215267e4c5ceabd4c5350331b2e4a0b6494c56f361fa5a57a1a201","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG","DERSIG","SIG_DER","BIP66 example 7, with DERSIG"], -["0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0x47 0x3044022079ea80afd538d9ada421b5101febeb6bc874e01dde5bca108c1d0479aec339a4022004576db8f66130d1df686ccf00935703689d69cf539438da1edab208b0d63c4801","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT","","EVAL_FALSE","BIP66 example 8, without DERSIG"], -["0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0x47 0x3044022079ea80afd538d9ada421b5101febeb6bc874e01dde5bca108c1d0479aec339a4022004576db8f66130d1df686ccf00935703689d69cf539438da1edab208b0d63c4801","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT","DERSIG","SIG_DER","BIP66 example 8, with DERSIG"], -["0 0 0x47 0x3044022081aa9d436f2154e8b6d600516db03d78de71df685b585a9807ead4210bd883490220534bb6bdf318a419ac0749660b60e78d17d515558ef369bf872eff405b676b2e01","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG","DERSIG","SIG_DER","BIP66 example 9, with DERSIG"], -["0 0 0x47 0x30440220da6f441dc3b4b2c84cfa8db0cd5b34ed92c9e01686de5a800d40498b70c0dcac02207c2cf91b0c32b860c4cd4994be36cfb84caf8bb7c3a8e4d96a31b2022c5299c501","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT","DERSIG","SIG_DER","BIP66 example 10, with DERSIG"], +["0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG","DERSIG","EVAL_FALSE","BIP66 example 11, with DERSIG"], +["0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT","DERSIG","OK","BIP66 example 12, with DERSIG"], ["0x48 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb12510101","0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG","","OK","P2PK with multi-byte hashtype, without DERSIG"], -["0x48 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb12510101","0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG","DERSIG","SIG_DER","P2PK with multi-byte hashtype, with DERSIG"], -["0x48 0x304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef001","0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG","","OK","P2PK with high S but no LOW_S"], ["0x48 0x304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef001","0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG","LOW_S","SIG_HIGH_S","P2PK with high S"], -["0x47 0x3044022057292e2d4dfe775becdd0a9e6547997c728cdf35390f6a017da56d654d374e4902206b643be2fc53763b4e284845bfea2c597d2dc7759941dce937636c9d341b71ed01","0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG","","OK","P2PK with hybrid pubkey but no STRICTENC"], ["0x47 0x3044022057292e2d4dfe775becdd0a9e6547997c728cdf35390f6a017da56d654d374e4902206b643be2fc53763b4e284845bfea2c597d2dc7759941dce937636c9d341b71ed01","0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG","STRICTENC","PUBKEYTYPE","P2PK with hybrid pubkey"], -["0x47 0x30440220035d554e3153c14950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101","0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT","","EVAL_FALSE","P2PK NOT with hybrid pubkey but no STRICTENC"], ["0x47 0x30440220035d554e3153c14950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101","0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT","STRICTENC","PUBKEYTYPE","P2PK NOT with hybrid pubkey"], ["0x47 0x30440220035d554e3153c04950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101","0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT","STRICTENC","PUBKEYTYPE","P2PK NOT with invalid hybrid pubkey"], -["0 0x47 0x304402202e79441ad1baf5a07fb86bae3753184f6717d9692680947ea8b6e8b777c69af1022079a262e13d868bb5a0964fefe3ba26942e1b0669af1afb55ef3344bc9d4fc4c401","1 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG","","OK","1-of-2 with the second 1 hybrid pubkey and no STRICTENC"], -["0 0x47 0x304402202e79441ad1baf5a07fb86bae3753184f6717d9692680947ea8b6e8b777c69af1022079a262e13d868bb5a0964fefe3ba26942e1b0669af1afb55ef3344bc9d4fc4c401","1 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG","STRICTENC","OK","1-of-2 with the second 1 hybrid pubkey"], -["0x47 0x304402206177d513ec2cda444c021a1f4f656fc4c72ba108ae063e157eb86dc3575784940220666fc66702815d0e5413bb9b1df22aed44f5f1efb8b99d41dd5dc9a5be6d205205","0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG","","OK","P2PK with undefined hashtype but no STRICTENC"], ["0x47 0x304402206177d513ec2cda444c021a1f4f656fc4c72ba108ae063e157eb86dc3575784940220666fc66702815d0e5413bb9b1df22aed44f5f1efb8b99d41dd5dc9a5be6d205205","0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG","STRICTENC","SIG_HASHTYPE","P2PK with undefined hashtype"], ["0x47 0x304402207409b5b320296e5e2136a7b281a7f803028ca4ca44e2b83eebd46932677725de02202d4eea1c8d3c98e6f42614f54764e6e5e6542e213eb4d079737e9a8b6e9812ec05","0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG NOT","STRICTENC","SIG_HASHTYPE","P2PK NOT with invalid sig and undefined hashtype"], -["1 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901","3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG","","OK","3-of-3 with nonzero dummy but no NULLDUMMY"], -["0 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901 DUP","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG","","OK","2-of-2 with two identical keys and sigs pushed using OP_DUP but no SIGPUSHONLY"], -["0x47 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb125101 NOP8","0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG","","OK","P2PK with non-push scriptSig but with P2SH validation"], -["0 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG","SIGPUSHONLY","OK","2-of-2 with two identical keys and sigs pushed"], -["11 0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001","0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG","P2SH","OK","P2PK with unnecessary input but no CLEANSTACK"], -["0x47 0x304402202f7505132be14872581f35d74b759212d9da40482653f1ffa3116c3294a4a51702206adbf347a2240ca41c66522b1a22a41693610b76a8e7770645dc721d1635854f01 0x43 0x410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac","HASH160 0x14 0x31edc23bdafda4639e669f89ad6b2318dd79d032 EQUAL","CLEANSTACK,P2SH","OK","P2SH with CLEANSTACK"], -[["304402200d461c140cfdfcf36b94961db57ae8c18d1cb80e9d95a9e47ac22470c1bf125502201c8dc1cbfef6a3ef90acbbb992ca22fe9466ee6f9d4898eda277a7ac3ab4b25101","410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac",1E-8],"","0 0x20 0xb95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64","P2SH,WITNESS","OK","Basic P2WSH"], -[["304402201e7216e5ccb3b61d46946ec6cc7e8c4e0117d13ac2fd4b152197e4805191c74202203e9903e33e84d9ee1dd13fb057afb7ccfb47006c23f6a067185efbc9dd780fc501","0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",1E-8],"","0 0x14 0x91b24bf9f5288532960ac687abb035127b1d28a5","P2SH,WITNESS","OK","Basic P2WPKH"], -[["3044022066e02c19a513049d49349cf5311a1b012b7c4fae023795a18ab1d91c23496c22022025e216342c8e07ce8ef51e8daee88f84306a9de66236cab230bb63067ded1ad301","410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac",1E-8],"0x22 0x0020b95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64","HASH160 0x14 0xf386c2ba255cc56d20cfa6ea8b062f8b59945518 EQUAL","P2SH,WITNESS","OK","Basic P2SH(P2WSH)"], -[["304402200929d11561cd958460371200f82e9cae64c727a495715a31828e27a7ad57b36d0220361732ced04a6f97351ecca21a56d0b8cd4932c1da1f8f569a2b68e5e48aed7801","0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",1E-8],"0x16 0x001491b24bf9f5288532960ac687abb035127b1d28a5","HASH160 0x14 0x17743beb429c55c942d2ec703b98c4d57c2df5c6 EQUAL","P2SH,WITNESS","OK","Basic P2SH(P2WPKH)"], -[["304402202589f0512cb2408fb08ed9bd24f85eb3059744d9e4f2262d0b7f1338cff6e8b902206c0978f449693e0578c71bc543b11079fd0baae700ee5e9a6bee94db490af9fc01","41048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26cafac",0E-8],"","0 0x20 0xac8ebd9e52c17619a381fa4f71aebb696087c6ef17c960fd0587addad99c0610","P2SH,WITNESS","EVAL_FALSE","Basic P2WSH with the wrong key"], -[["304402206ef7fdb2986325d37c6eb1a8bb24aeb46dede112ed8fc76c7d7500b9b83c0d3d02201edc2322c794fe2d6b0bd73ed319e714aa9b86d8891961530d5c9b7156b60d4e01","048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf",0E-8],"","0 0x14 0x7cf9c846cd4882efec4bf07e44ebdad495c94f4b","P2SH,WITNESS","EVAL_FALSE","Basic P2WPKH with the wrong key"], -[["30440220069ea3581afaf8187f63feee1fd2bd1f9c0dc71ea7d6e8a8b07ee2ebcf824bf402201a4fdef4c532eae59223be1eda6a397fc835142d4ddc6c74f4aa85b766a5c16f01","41048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26cafac",0E-8],"0x22 0x0020ac8ebd9e52c17619a381fa4f71aebb696087c6ef17c960fd0587addad99c0610","HASH160 0x14 0x61039a003883787c0d6ebc66d97fdabe8e31449d EQUAL","P2SH,WITNESS","EVAL_FALSE","Basic P2SH(P2WSH) with the wrong key"], -[["304402204209e49457c2358f80d0256bc24535b8754c14d08840fc4be762d6f5a0aed80b02202eaf7d8fc8d62f60c67adcd99295528d0e491ae93c195cec5a67e7a09532a88001","048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf",0E-8],"0x16 0x00147cf9c846cd4882efec4bf07e44ebdad495c94f4b","HASH160 0x14 0x4e0c2aed91315303fc6a1dc4c7bc21c88f75402e EQUAL","P2SH,WITNESS","EVAL_FALSE","Basic P2SH(P2WPKH) with the wrong key"], -[["3044022066faa86e74e8b30e82691b985b373de4f9e26dc144ec399c4f066aa59308e7c202204712b86f28c32503faa051dbeabff2c238ece861abc36c5e0b40b1139ca222f001","410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac",0E-8],"","0 0x20 0xb95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64","P2SH,WITNESS","EVAL_FALSE","Basic P2WSH with wrong value"], -[["304402203b3389b87448d7dfdb5e82fb854fcf92d7925f9938ea5444e36abef02c3d6a9602202410bc3265049abb07fd2e252c65ab7034d95c9d5acccabe9fadbdc63a52712601","0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",0E-8],"","0 0x14 0x91b24bf9f5288532960ac687abb035127b1d28a5","P2SH,WITNESS","EVAL_FALSE","Basic P2WPKH with wrong value"], -[["3044022000a30c4cfc10e4387be528613575434826ad3c15587475e0df8ce3b1746aa210022008149265e4f8e9dafe1f3ea50d90cb425e9e40ea7ebdd383069a7cfa2b77004701","410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac",0E-8],"0x22 0x0020b95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64","HASH160 0x14 0xf386c2ba255cc56d20cfa6ea8b062f8b59945518 EQUAL","P2SH,WITNESS","EVAL_FALSE","Basic P2SH(P2WSH) with wrong value"], -[["304402204fc3a2cd61a47913f2a5f9107d0ad4a504c7b31ee2d6b3b2f38c2b10ee031e940220055d58b7c3c281aaa381d8f486ac0f3e361939acfd568046cb6a311cdfa974cf01","0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",0E-8],"0x16 0x001491b24bf9f5288532960ac687abb035127b1d28a5","HASH160 0x14 0x17743beb429c55c942d2ec703b98c4d57c2df5c6 EQUAL","P2SH,WITNESS","EVAL_FALSE","Basic P2SH(P2WPKH) with wrong value"], [["304402205ae57ae0534c05ca9981c8a6cdf353b505eaacb7375f96681a2d1a4ba6f02f84022056248e68643b7d8ce7c7d128c9f1f348bcab8be15d094ad5cadd24251a28df8001","0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",0E-8],"","1 0x14 0x91b24bf9f5288532960ac687abb035127b1d28a5","DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM,P2SH,WITNESS","DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM","P2WPKH with future witness version"], [["3044022064100ca0e2a33332136775a86cd83d0230e58b9aebb889c5ac952abff79a46ef02205f1bf900e022039ad3091bdaf27ac2aef3eae9ed9f190d821d3e508405b9513101","0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",0E-8],"","0 0x1f 0xb34b78da162751647974d5cb7410aa428ad339dbf7d1e16e833f68a0cbf1c3","P2SH,WITNESS","WITNESS_PROGRAM_WRONG_LENGTH","P2WPKH with wrong witness program length"], ["","0 0x20 0xb95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64","P2SH,WITNESS","WITNESS_PROGRAM_WITNESS_EMPTY","P2WSH with empty witness"], -[["3044022039105b995a5f448639a997a5c90fda06f50b49df30c3bdb6663217bf79323db002206fecd54269dec569fcc517178880eb58bb40f381a282bb75766ff3637d5f4b4301","400479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac",0E-8],"","0 0x20 0xb95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64","P2SH,WITNESS","WITNESS_PROGRAM_MISMATCH","P2WSH with witness program mismatch"], -[["304402201a96950593cb0af32d080b0f193517f4559241a8ebd1e95e414533ad64a3f423022047f4f6d3095c23235bdff3aeff480d0529c027a3f093cb265b7cbf148553b85101","0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8","",0E-8],"","0 0x14 0x91b24bf9f5288532960ac687abb035127b1d28a5","P2SH,WITNESS","WITNESS_PROGRAM_MISMATCH","P2WPKH with witness program mismatch"], -[["304402201a96950593cb0af32d080b0f193517f4559241a8ebd1e95e414533ad64a3f423022047f4f6d3095c23235bdff3aeff480d0529c027a3f093cb265b7cbf148553b85101","0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",0E-8],"11","0 0x14 0x91b24bf9f5288532960ac687abb035127b1d28a5","P2SH,WITNESS","WITNESS_MALLEATED","P2WPKH with non-empty scriptSig"], [["304402204209e49457c2358f80d0256bc24535b8754c14d08840fc4be762d6f5a0aed80b02202eaf7d8fc8d62f60c67adcd99295528d0e491ae93c195cec5a67e7a09532a88001","048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf",0E-8],"11 0x16 0x00147cf9c846cd4882efec4bf07e44ebdad495c94f4b","HASH160 0x14 0x4e0c2aed91315303fc6a1dc4c7bc21c88f75402e EQUAL","P2SH,WITNESS","WITNESS_MALLEATED_P2SH","P2SH(P2WPKH) with superfluous push in scriptSig"], -[["",0E-8],"0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001","0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG","P2SH,WITNESS","WITNESS_UNEXPECTED","P2PK with witness"], -[["304402204256146fcf8e73b0fd817ffa2a4e408ff0418ff987dd08a4f485b62546f6c43c02203f3c8c3e2febc051e1222867f5f9d0eaf039d6792911c10940aa3cc74123378e01","210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac",1E-8],"","0 0x20 0x1863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262","P2SH,WITNESS,WITNESS_PUBKEYTYPE","OK","Basic P2WSH with compressed key"], -[["304402204edf27486f11432466b744df533e1acac727e0c83e5f912eb289a3df5bf8035f022075809fdd876ede40ad21667eba8b7e96394938f9c9c50f11b6a1280cce2cea8601","0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",1E-8],"","0 0x14 0x751e76e8199196d454941c45d1b3a323f1433bd6","P2SH,WITNESS,WITNESS_PUBKEYTYPE","OK","Basic P2WPKH with compressed key"], -[["304402203a549090cc46bce1e5e95c4922ea2c12747988e0207b04c42f81cdbe87bb1539022050f57a245b875fd5119c419aaf050bcdf41384f0765f04b809e5bced1fe7093d01","210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac",1E-8],"0x22 0x00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262","HASH160 0x14 0xe4300531190587e3880d4c3004f5355d88ff928d EQUAL","P2SH,WITNESS,WITNESS_PUBKEYTYPE","OK","Basic P2SH(P2WSH) with compressed key"], -[["304402201bc0d53046827f4a35a3166e33e3b3366c4085540dc383b95d21ed2ab11e368a0220333e78c6231214f5f8e59621e15d7eeab0d4e4d0796437e00bfbd2680c5f9c1701","0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",1E-8],"0x16 0x0014751e76e8199196d454941c45d1b3a323f1433bd6","HASH160 0x14 0xbcfeb728b584253d5f3f70bcb780e9ef218a68f4 EQUAL","P2SH,WITNESS,WITNESS_PUBKEYTYPE","OK","Basic P2SH(P2WPKH) with compressed key"], [["304402200d461c140cfdfcf36b94961db57ae8c18d1cb80e9d95a9e47ac22470c1bf125502201c8dc1cbfef6a3ef90acbbb992ca22fe9466ee6f9d4898eda277a7ac3ab4b25101","410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac",1E-8],"","0 0x20 0xb95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64","P2SH,WITNESS,WITNESS_PUBKEYTYPE","WITNESS_PUBKEYTYPE","Basic P2WSH"], [["304402201e7216e5ccb3b61d46946ec6cc7e8c4e0117d13ac2fd4b152197e4805191c74202203e9903e33e84d9ee1dd13fb057afb7ccfb47006c23f6a067185efbc9dd780fc501","0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",1E-8],"","0 0x14 0x91b24bf9f5288532960ac687abb035127b1d28a5","P2SH,WITNESS,WITNESS_PUBKEYTYPE","WITNESS_PUBKEYTYPE","Basic P2WPKH"], [["3044022066e02c19a513049d49349cf5311a1b012b7c4fae023795a18ab1d91c23496c22022025e216342c8e07ce8ef51e8daee88f84306a9de66236cab230bb63067ded1ad301","410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac",1E-8],"0x22 0x0020b95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64","HASH160 0x14 0xf386c2ba255cc56d20cfa6ea8b062f8b59945518 EQUAL","P2SH,WITNESS,WITNESS_PUBKEYTYPE","WITNESS_PUBKEYTYPE","Basic P2SH(P2WSH)"], @@ -117,61 +38,7 @@ [["","30440220687871bc6144012d75baf585bb26ce13997f7d8c626f4d8825b069c3b2d064470220108936fe1c57327764782253e99090b09c203ec400ed35ce9e026ce2ecf842a001","5141048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179852ae",1E-8],"0x22 0x0020230828ed48871f0f362ce9432aa52f620f442cc8d9ce7a8b5e798365595a38bb","HASH160 0x14 0x3478e7019ce61a68148f87549579b704cbe4c393 EQUAL","P2SH,WITNESS,WITNESS_PUBKEYTYPE","WITNESS_PUBKEYTYPE","P2SH(P2WSH) CHECKMULTISIG with second key uncompressed and signing with the second key"], ["0","CHECKSEQUENCEVERIFY","CHECKSEQUENCEVERIFY","UNSATISFIED_LOCKTIME","CSV fails if stack top bit 1 << 31 is set and the tx version < 2"], ["0x050000000001","CHECKSEQUENCEVERIFY","CHECKSEQUENCEVERIFY","UNSATISFIED_LOCKTIME","CSV fails if stack top bit 1 << 31 is not set, and tx version < 2"], -["0 0x03 0x635168","HASH160 0x14 0xe7309652a8e3f600f06f5d8d52d6df03d2176cc3 EQUAL","P2SH,WITNESS,MINIMALIF","EVAL_FALSE"], -["0x01 0x00 0x03 0x635168","HASH160 0x14 0xe7309652a8e3f600f06f5d8d52d6df03d2176cc3 EQUAL","P2SH,WITNESS,MINIMALIF","EVAL_FALSE"], -["0x03 0x635168","HASH160 0x14 0xe7309652a8e3f600f06f5d8d52d6df03d2176cc3 EQUAL","P2SH,WITNESS,MINIMALIF","UNBALANCED_CONDITIONAL"], -["1 0x03 0x645168","HASH160 0x14 0x0c3f8fe3d6ca266e76311ecda544c67d15fdd5b0 EQUAL","P2SH,WITNESS,MINIMALIF","EVAL_FALSE"], -["2 0x03 0x645168","HASH160 0x14 0x0c3f8fe3d6ca266e76311ecda544c67d15fdd5b0 EQUAL","P2SH,WITNESS,MINIMALIF","EVAL_FALSE"], -["0x02 0x0100 0x03 0x645168","HASH160 0x14 0x0c3f8fe3d6ca266e76311ecda544c67d15fdd5b0 EQUAL","P2SH,WITNESS,MINIMALIF","EVAL_FALSE"], -["0x03 0x645168","HASH160 0x14 0x0c3f8fe3d6ca266e76311ecda544c67d15fdd5b0 EQUAL","P2SH,WITNESS,MINIMALIF","UNBALANCED_CONDITIONAL"], -[["01","635168",1E-8],"","0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","P2SH,WITNESS","OK"], -[["02","635168",1E-8],"","0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","P2SH,WITNESS","OK"], -[["0100","635168",1E-8],"","0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","P2SH,WITNESS","OK"], -[["","635168",1E-8],"","0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","P2SH,WITNESS","CLEANSTACK"], -[["00","635168",1E-8],"","0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","P2SH,WITNESS","CLEANSTACK"], -[["01","635168",1E-8],"","0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","P2SH,WITNESS,MINIMALIF","OK"], -[["02","635168",1E-8],"","0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","P2SH,WITNESS,MINIMALIF","MINIMALIF"], -[["0100","635168",1E-8],"","0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","P2SH,WITNESS,MINIMALIF","MINIMALIF"], -[["","635168",1E-8],"","0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","P2SH,WITNESS,MINIMALIF","CLEANSTACK"], -[["00","635168",1E-8],"","0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","P2SH,WITNESS,MINIMALIF","MINIMALIF"], -[["635168",1E-8],"","0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","P2SH,WITNESS","UNBALANCED_CONDITIONAL"], -[["635168",1E-8],"","0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","P2SH,WITNESS,MINIMALIF","UNBALANCED_CONDITIONAL"], -[["01","645168",1E-8],"","0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","P2SH,WITNESS","CLEANSTACK"], -[["02","645168",1E-8],"","0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","P2SH,WITNESS","CLEANSTACK"], -[["0100","645168",1E-8],"","0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","P2SH,WITNESS","CLEANSTACK"], -[["","645168",1E-8],"","0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","P2SH,WITNESS","OK"], -[["00","645168",1E-8],"","0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","P2SH,WITNESS","OK"], -[["01","645168",1E-8],"","0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","P2SH,WITNESS,MINIMALIF","CLEANSTACK"], -[["02","645168",1E-8],"","0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","P2SH,WITNESS,MINIMALIF","MINIMALIF"], -[["0100","645168",1E-8],"","0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","P2SH,WITNESS,MINIMALIF","MINIMALIF"], -[["","645168",1E-8],"","0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","P2SH,WITNESS,MINIMALIF","OK"], -[["00","645168",1E-8],"","0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","P2SH,WITNESS,MINIMALIF","MINIMALIF"], -[["645168",1E-8],"","0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","P2SH,WITNESS","UNBALANCED_CONDITIONAL"], -[["645168",1E-8],"","0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","P2SH,WITNESS,MINIMALIF","UNBALANCED_CONDITIONAL"], -[["01","635168",1E-8],"0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL","P2SH,WITNESS","OK"], -[["02","635168",1E-8],"0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL","P2SH,WITNESS","OK"], -[["0100","635168",1E-8],"0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL","P2SH,WITNESS","OK"], -[["","635168",1E-8],"0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL","P2SH,WITNESS","CLEANSTACK"], -[["00","635168",1E-8],"0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL","P2SH,WITNESS","CLEANSTACK"], -[["01","635168",1E-8],"0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL","P2SH,WITNESS,MINIMALIF","OK"], -[["02","635168",1E-8],"0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL","P2SH,WITNESS,MINIMALIF","MINIMALIF"], -[["0100","635168",1E-8],"0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL","P2SH,WITNESS,MINIMALIF","MINIMALIF"], -[["","635168",1E-8],"0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL","P2SH,WITNESS,MINIMALIF","CLEANSTACK"], -[["00","635168",1E-8],"0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL","P2SH,WITNESS,MINIMALIF","MINIMALIF"], -[["635168",1E-8],"0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL","P2SH,WITNESS","UNBALANCED_CONDITIONAL"], -[["635168",1E-8],"0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL","P2SH,WITNESS,MINIMALIF","UNBALANCED_CONDITIONAL"], -[["01","645168",1E-8],"0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL","P2SH,WITNESS","CLEANSTACK"], -[["02","645168",1E-8],"0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL","P2SH,WITNESS","CLEANSTACK"], -[["0100","645168",1E-8],"0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL","P2SH,WITNESS","CLEANSTACK"], -[["","645168",1E-8],"0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL","P2SH,WITNESS","OK"], -[["00","645168",1E-8],"0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL","P2SH,WITNESS","OK"], -[["01","645168",1E-8],"0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL","P2SH,WITNESS,MINIMALIF","CLEANSTACK"], -[["02","645168",1E-8],"0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL","P2SH,WITNESS,MINIMALIF","MINIMALIF"], -[["0100","645168",1E-8],"0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL","P2SH,WITNESS,MINIMALIF","MINIMALIF"], -[["","645168",1E-8],"0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL","P2SH,WITNESS,MINIMALIF","OK"], -[["00","645168",1E-8],"0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL","P2SH,WITNESS,MINIMALIF","MINIMALIF"], -[["645168",1E-8],"0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL","P2SH,WITNESS","UNBALANCED_CONDITIONAL"], -[["645168",1E-8],"0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL","P2SH,WITNESS,MINIMALIF","UNBALANCED_CONDITIONAL"], +["0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0","0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT","DERSIG","OK","BIP66 and NULLFAIL-compliant"], ["0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0x09 0x300602010102010101","0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT","DERSIG","OK","BIP66-compliant but not NULLFAIL-compliant"], -["0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0x09 0x300602010102010101","0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT","DERSIG,NULLFAIL","NULLFAIL","BIP66-compliant but not NULLFAIL-compliant"] -] +["0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0x09 0x300602010102010101","0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT","DERSIG,NULLFAIL","NULLFAIL","BIP66-compliant but not NULLFAIL-compliant"], +["0 0x09 0x300602010102010101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0","0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT","DERSIG","OK","BIP66-compliant but not NULLFAIL-compliant"], diff --git a/tests/script_tests_passing.json b/tests/script_tests_passing.json new file mode 100644 index 00000000..59c82ab5 --- /dev/null +++ b/tests/script_tests_passing.json @@ -0,0 +1,1163 @@ +["","DEPTH 0 EQUAL","P2SH,STRICTENC","OK","Test the test: we should have an empty stack after scriptSig evaluation"], +[" ","DEPTH 0 EQUAL","P2SH,STRICTENC","OK","and multiple spaces should not change that."], +[" ","DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +[" ","DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["1 2","2 EQUALVERIFY 1 EQUAL","P2SH,STRICTENC","OK","Similarly whitespace around and between symbols"], +["1 2","2 EQUALVERIFY 1 EQUAL","P2SH,STRICTENC","OK"], +[" 1 2","2 EQUALVERIFY 1 EQUAL","P2SH,STRICTENC","OK"], +["1 2 ","2 EQUALVERIFY 1 EQUAL","P2SH,STRICTENC","OK"], +[" 1 2 ","2 EQUALVERIFY 1 EQUAL","P2SH,STRICTENC","OK"], +["1","","P2SH,STRICTENC","OK"], +["0x02 0x01 0x00","","P2SH,STRICTENC","OK","all bytes are significant, not only the last one"], +["0x09 0x00000000 0x00000000 0x10","","P2SH,STRICTENC","OK","equals zero when cast to Int64"], +["0x01 0x0b","11 EQUAL","P2SH,STRICTENC","OK","push 1 byte"], +["0x02 0x417a","'Az' EQUAL","P2SH,STRICTENC","OK"], +["0x4b 0x417a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a","'Azzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz' EQUAL","P2SH,STRICTENC","OK","push 75 bytes"], +["0x4c 0x01 0x07","7 EQUAL","P2SH,STRICTENC","OK","0x4c is OP_PUSHDATA1"], +["0x4d 0x0100 0x08","8 EQUAL","P2SH,STRICTENC","OK","0x4d is OP_PUSHDATA2"], +["0x4e 0x01000000 0x09","9 EQUAL","P2SH,STRICTENC","OK","0x4e is OP_PUSHDATA4"], +["0x4c 0x00","0 EQUAL","P2SH,STRICTENC","OK"], +["0x4d 0x0000","0 EQUAL","P2SH,STRICTENC","OK"], +["0x4e 0x00000000","0 EQUAL","P2SH,STRICTENC","OK"], +["0x4f 1000 ADD","999 EQUAL","P2SH,STRICTENC","OK"], +["0","IF 0x50 ENDIF 1","P2SH,STRICTENC","OK","0x50 is reserved (ok if not executed)"], +["0x51","0x5f ADD 0x60 EQUAL","P2SH,STRICTENC","OK","0x51 through 0x60 push 1 through 16 onto stack"], +["1","NOP","P2SH,STRICTENC","OK"], +["0","IF VER ELSE 1 ENDIF","P2SH,STRICTENC","OK","VER non-functional (ok if not executed)"], +["0","IF RESERVED RESERVED1 RESERVED2 ELSE 1 ENDIF","P2SH,STRICTENC","OK","RESERVED ok in un-executed IF"], +["1","DUP IF ENDIF","P2SH,STRICTENC","OK"], +["1","IF 1 ENDIF","P2SH,STRICTENC","OK"], +["1","DUP IF ELSE ENDIF","P2SH,STRICTENC","OK"], +["1","IF 1 ELSE ENDIF","P2SH,STRICTENC","OK"], +["0","IF ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["1 1","IF IF 1 ELSE 0 ENDIF ENDIF","P2SH,STRICTENC","OK"], +["1 0","IF IF 1 ELSE 0 ENDIF ENDIF","P2SH,STRICTENC","OK"], +["1 1","IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF","P2SH,STRICTENC","OK"], +["0 0","IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF","P2SH,STRICTENC","OK"], +["1 0","NOTIF IF 1 ELSE 0 ENDIF ENDIF","P2SH,STRICTENC","OK"], +["1 1","NOTIF IF 1 ELSE 0 ENDIF ENDIF","P2SH,STRICTENC","OK"], +["1 0","NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF","P2SH,STRICTENC","OK"], +["0 1","NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0 ELSE 1 ELSE 0 ENDIF","P2SH,STRICTENC","OK","Multiple ELSE's are valid and executed inverts on each ELSE encountered"], +["1","IF 1 ELSE 0 ELSE ENDIF","P2SH,STRICTENC","OK"], +["1","IF ELSE 0 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["1","IF 1 ELSE 0 ELSE 1 ENDIF ADD 2 EQUAL","P2SH,STRICTENC","OK"], +["'' 1","IF SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ENDIF 0x14 0x68ca4fec736264c13b859bac43d5173df6871682 EQUAL","P2SH,STRICTENC","OK"], +["1","NOTIF 0 ELSE 1 ELSE 0 ENDIF","P2SH,STRICTENC","OK","Multiple ELSE's are valid and execution inverts on each ELSE encountered"], +["0","NOTIF 1 ELSE 0 ELSE ENDIF","P2SH,STRICTENC","OK"], +["0","NOTIF ELSE 0 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","NOTIF 1 ELSE 0 ELSE 1 ENDIF ADD 2 EQUAL","P2SH,STRICTENC","OK"], +["'' 0","NOTIF SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ENDIF 0x14 0x68ca4fec736264c13b859bac43d5173df6871682 EQUAL","P2SH,STRICTENC","OK"], +["0","IF 1 IF RETURN ELSE RETURN ELSE RETURN ENDIF ELSE 1 IF 1 ELSE RETURN ELSE 1 ENDIF ELSE RETURN ENDIF ADD 2 EQUAL","P2SH,STRICTENC","OK","Nested ELSE ELSE"], +["1","NOTIF 0 NOTIF RETURN ELSE RETURN ELSE RETURN ENDIF ELSE 0 NOTIF 1 ELSE RETURN ELSE 1 ENDIF ELSE RETURN ENDIF ADD 2 EQUAL","P2SH,STRICTENC","OK"], +["0","IF RETURN ENDIF 1","P2SH,STRICTENC","OK","RETURN only works if executed"], +["1 1","VERIFY","P2SH,STRICTENC","OK"], +["1 0x05 0x01 0x00 0x00 0x00 0x00","VERIFY","P2SH,STRICTENC","OK","values >4 bytes can be cast to boolean"], +["1 0x01 0x80","IF 0 ENDIF","P2SH,STRICTENC","OK","negative 0 is false"], +["10 0 11 TOALTSTACK DROP FROMALTSTACK","ADD 21 EQUAL","P2SH,STRICTENC","OK"], +["'gavin_was_here' TOALTSTACK 11 FROMALTSTACK","'gavin_was_here' EQUALVERIFY 11 EQUAL","P2SH,STRICTENC","OK"], +["0 IFDUP","DEPTH 1 EQUALVERIFY 0 EQUAL","P2SH,STRICTENC","OK"], +["1 IFDUP","DEPTH 2 EQUALVERIFY 1 EQUALVERIFY 1 EQUAL","P2SH,STRICTENC","OK"], +["0x05 0x0100000000 IFDUP","DEPTH 2 EQUALVERIFY 0x05 0x0100000000 EQUAL","P2SH,STRICTENC","OK","IFDUP dups non ints"], +["0 DROP","DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["0","DUP 1 ADD 1 EQUALVERIFY 0 EQUAL","P2SH,STRICTENC","OK"], +["0 1","NIP","P2SH,STRICTENC","OK"], +["1 0","OVER DEPTH 3 EQUALVERIFY","P2SH,STRICTENC","OK"], +["22 21 20","0 PICK 20 EQUALVERIFY DEPTH 3 EQUAL","P2SH,STRICTENC","OK"], +["22 21 20","1 PICK 21 EQUALVERIFY DEPTH 3 EQUAL","P2SH,STRICTENC","OK"], +["22 21 20","2 PICK 22 EQUALVERIFY DEPTH 3 EQUAL","P2SH,STRICTENC","OK"], +["22 21 20","0 ROLL 20 EQUALVERIFY DEPTH 2 EQUAL","P2SH,STRICTENC","OK"], +["22 21 20","1 ROLL 21 EQUALVERIFY DEPTH 2 EQUAL","P2SH,STRICTENC","OK"], +["22 21 20","2 ROLL 22 EQUALVERIFY DEPTH 2 EQUAL","P2SH,STRICTENC","OK"], +["22 21 20","ROT 22 EQUAL","P2SH,STRICTENC","OK"], +["22 21 20","ROT DROP 20 EQUAL","P2SH,STRICTENC","OK"], +["22 21 20","ROT DROP DROP 21 EQUAL","P2SH,STRICTENC","OK"], +["22 21 20","ROT ROT 21 EQUAL","P2SH,STRICTENC","OK"], +["22 21 20","ROT ROT ROT 20 EQUAL","P2SH,STRICTENC","OK"], +["25 24 23 22 21 20","2ROT 24 EQUAL","P2SH,STRICTENC","OK"], +["25 24 23 22 21 20","2ROT DROP 25 EQUAL","P2SH,STRICTENC","OK"], +["25 24 23 22 21 20","2ROT 2DROP 20 EQUAL","P2SH,STRICTENC","OK"], +["25 24 23 22 21 20","2ROT 2DROP DROP 21 EQUAL","P2SH,STRICTENC","OK"], +["25 24 23 22 21 20","2ROT 2DROP 2DROP 22 EQUAL","P2SH,STRICTENC","OK"], +["25 24 23 22 21 20","2ROT 2DROP 2DROP DROP 23 EQUAL","P2SH,STRICTENC","OK"], +["25 24 23 22 21 20","2ROT 2ROT 22 EQUAL","P2SH,STRICTENC","OK"], +["25 24 23 22 21 20","2ROT 2ROT 2ROT 20 EQUAL","P2SH,STRICTENC","OK"], +["1 0","SWAP 1 EQUALVERIFY 0 EQUAL","P2SH,STRICTENC","OK"], +["0 1","TUCK DEPTH 3 EQUALVERIFY SWAP 2DROP","P2SH,STRICTENC","OK"], +["13 14","2DUP ROT EQUALVERIFY EQUAL","P2SH,STRICTENC","OK"], +["-1 0 1 2","3DUP DEPTH 7 EQUALVERIFY ADD ADD 3 EQUALVERIFY 2DROP 0 EQUALVERIFY","P2SH,STRICTENC","OK"], +["1 2 3 5","2OVER ADD ADD 8 EQUALVERIFY ADD ADD 6 EQUAL","P2SH,STRICTENC","OK"], +["1 3 5 7","2SWAP ADD 4 EQUALVERIFY ADD 12 EQUAL","P2SH,STRICTENC","OK"], +["0","SIZE 0 EQUAL","P2SH,STRICTENC","OK"], +["1","SIZE 1 EQUAL","P2SH,STRICTENC","OK"], +["127","SIZE 1 EQUAL","P2SH,STRICTENC","OK"], +["128","SIZE 2 EQUAL","P2SH,STRICTENC","OK"], +["32767","SIZE 2 EQUAL","P2SH,STRICTENC","OK"], +["32768","SIZE 3 EQUAL","P2SH,STRICTENC","OK"], +["8388607","SIZE 3 EQUAL","P2SH,STRICTENC","OK"], +["8388608","SIZE 4 EQUAL","P2SH,STRICTENC","OK"], +["2147483647","SIZE 4 EQUAL","P2SH,STRICTENC","OK"], +["2147483648","SIZE 5 EQUAL","P2SH,STRICTENC","OK"], +["0x05ffffffff7f","SIZE 5 EQUAL","P2SH,STRICTENC","OK"], +["0x06000000008000","SIZE 6 EQUAL","P2SH,STRICTENC","OK"], +["0x08ffffffffffffff7f","SIZE 8 EQUAL","P2SH,STRICTENC","OK"], +["-1","SIZE 1 EQUAL","P2SH,STRICTENC","OK"], +["-127","SIZE 1 EQUAL","P2SH,STRICTENC","OK"], +["-128","SIZE 2 EQUAL","P2SH,STRICTENC","OK"], +["-32767","SIZE 2 EQUAL","P2SH,STRICTENC","OK"], +["-32768","SIZE 3 EQUAL","P2SH,STRICTENC","OK"], +["-8388607","SIZE 3 EQUAL","P2SH,STRICTENC","OK"], +["-8388608","SIZE 4 EQUAL","P2SH,STRICTENC","OK"], +["-2147483647","SIZE 4 EQUAL","P2SH,STRICTENC","OK"], +["-2147483648","SIZE 5 EQUAL","P2SH,STRICTENC","OK"], +["0x05ffffffffff","SIZE 5 EQUAL","P2SH,STRICTENC","OK"], +["0x06000000008080","SIZE 6 EQUAL","P2SH,STRICTENC","OK"], +["0x08ffffffffffffffff","SIZE 8 EQUAL","P2SH,STRICTENC","OK"], +["'abcdefghijklmnopqrstuvwxyz'","SIZE 26 EQUAL","P2SH,STRICTENC","OK"], +["42","SIZE 1 EQUALVERIFY 42 EQUAL","P2SH,STRICTENC","OK","SIZE does not consume argument"], +["2 -2 ADD","0 EQUAL","P2SH,STRICTENC","OK"], +["2147483647 -2147483647 ADD","0 EQUAL","P2SH,STRICTENC","OK"], +["-1 -1 ADD","-2 EQUAL","P2SH,STRICTENC","OK"], +["0 0","EQUAL","P2SH,STRICTENC","OK"], +["1 1 ADD","2 EQUAL","P2SH,STRICTENC","OK"], +["1 1ADD","2 EQUAL","P2SH,STRICTENC","OK"], +["111 1SUB","110 EQUAL","P2SH,STRICTENC","OK"], +["111 1 ADD 12 SUB","100 EQUAL","P2SH,STRICTENC","OK"], +["0 ABS","0 EQUAL","P2SH,STRICTENC","OK"], +["16 ABS","16 EQUAL","P2SH,STRICTENC","OK"], +["-16 ABS","-16 NEGATE EQUAL","P2SH,STRICTENC","OK"], +["0 NOT","NOP","P2SH,STRICTENC","OK"], +["1 NOT","0 EQUAL","P2SH,STRICTENC","OK"], +["11 NOT","0 EQUAL","P2SH,STRICTENC","OK"], +["0 0NOTEQUAL","0 EQUAL","P2SH,STRICTENC","OK"], +["1 0NOTEQUAL","1 EQUAL","P2SH,STRICTENC","OK"], +["111 0NOTEQUAL","1 EQUAL","P2SH,STRICTENC","OK"], +["-111 0NOTEQUAL","1 EQUAL","P2SH,STRICTENC","OK"], +["1 1 BOOLAND","NOP","P2SH,STRICTENC","OK"], +["1 0 BOOLAND","NOT","P2SH,STRICTENC","OK"], +["0 1 BOOLAND","NOT","P2SH,STRICTENC","OK"], +["0 0 BOOLAND","NOT","P2SH,STRICTENC","OK"], +["16 17 BOOLAND","NOP","P2SH,STRICTENC","OK"], +["1 1 BOOLOR","NOP","P2SH,STRICTENC","OK"], +["1 0 BOOLOR","NOP","P2SH,STRICTENC","OK"], +["0 1 BOOLOR","NOP","P2SH,STRICTENC","OK"], +["0 0 BOOLOR","NOT","P2SH,STRICTENC","OK"], +["0x01 0x80","DUP BOOLOR","P2SH,STRICTENC","EVAL_FALSE","negative-0 negative-0 BOOLOR"], +["0x01 0x00","DUP BOOLOR","P2SH,STRICTENC","EVAL_FALSE"," non-minimal-0 non-minimal-0 BOOLOR"], +["0x01 0x81","DUP BOOLOR","P2SH,STRICTENC","OK","-1 -1 BOOLOR"], +["0x01 0x80","DUP BOOLAND","P2SH,STRICTENC","EVAL_FALSE","negative-0 negative-0 BOOLAND"], +["0x01 0x00","DUP BOOLAND","P2SH,STRICTENC","EVAL_FALSE"," non-minimal-0 non-minimal-0 BOOLAND"], +["0x01 0x81","DUP BOOLAND","P2SH,STRICTENC","OK","-1 -1 BOOLAND"], +["0x01 0x00","NOT","P2SH,STRICTENC","OK","non-minimal-0 NOT"], +["0x01 0x80","NOT","P2SH,STRICTENC","OK","negative-0 NOT"], +["0x01 0x81","NOT","P2SH,STRICTENC","EVAL_FALSE","negative 1 NOT"], +["0x01 0x80 0","NUMEQUAL","P2SH","OK","-0 0 NUMEQUAL"], +["0x01 0x00 0","NUMEQUAL","P2SH","OK","non-minimal-0 0 NUMEQUAL"], +["0x02 0x00 0x00 0","NUMEQUAL","P2SH","OK","non-minimal-0 0 NUMEQUAL"], +["16 17 BOOLOR","NOP","P2SH,STRICTENC","OK"], +["11 10 1 ADD","NUMEQUAL","P2SH,STRICTENC","OK"], +["11 10 1 ADD","NUMEQUALVERIFY 1","P2SH,STRICTENC","OK"], +["11 10 1 ADD","NUMNOTEQUAL NOT","P2SH,STRICTENC","OK"], +["111 10 1 ADD","NUMNOTEQUAL","P2SH,STRICTENC","OK"], +["11 10","LESSTHAN NOT","P2SH,STRICTENC","OK"], +["4 4","LESSTHAN NOT","P2SH,STRICTENC","OK"], +["10 11","LESSTHAN","P2SH,STRICTENC","OK"], +["-11 11","LESSTHAN","P2SH,STRICTENC","OK"], +["-11 -10","LESSTHAN","P2SH,STRICTENC","OK"], +["11 10","GREATERTHAN","P2SH,STRICTENC","OK"], +["4 4","GREATERTHAN NOT","P2SH,STRICTENC","OK"], +["10 11","GREATERTHAN NOT","P2SH,STRICTENC","OK"], +["-11 11","GREATERTHAN NOT","P2SH,STRICTENC","OK"], +["-11 -10","GREATERTHAN NOT","P2SH,STRICTENC","OK"], +["11 10","LESSTHANOREQUAL NOT","P2SH,STRICTENC","OK"], +["4 4","LESSTHANOREQUAL","P2SH,STRICTENC","OK"], +["10 11","LESSTHANOREQUAL","P2SH,STRICTENC","OK"], +["-11 11","LESSTHANOREQUAL","P2SH,STRICTENC","OK"], +["-11 -10","LESSTHANOREQUAL","P2SH,STRICTENC","OK"], +["11 10","GREATERTHANOREQUAL","P2SH,STRICTENC","OK"], +["4 4","GREATERTHANOREQUAL","P2SH,STRICTENC","OK"], +["10 11","GREATERTHANOREQUAL NOT","P2SH,STRICTENC","OK"], +["-11 11","GREATERTHANOREQUAL NOT","P2SH,STRICTENC","OK"], +["-11 -10","GREATERTHANOREQUAL NOT","P2SH,STRICTENC","OK"], +["1 0 MIN","0 NUMEQUAL","P2SH,STRICTENC","OK"], +["0 1 MIN","0 NUMEQUAL","P2SH,STRICTENC","OK"], +["-1 0 MIN","-1 NUMEQUAL","P2SH,STRICTENC","OK"], +["0 -2147483647 MIN","-2147483647 NUMEQUAL","P2SH,STRICTENC","OK"], +["2147483647 0 MAX","2147483647 NUMEQUAL","P2SH,STRICTENC","OK"], +["0 100 MAX","100 NUMEQUAL","P2SH,STRICTENC","OK"], +["-100 0 MAX","0 NUMEQUAL","P2SH,STRICTENC","OK"], +["0 -2147483647 MAX","0 NUMEQUAL","P2SH,STRICTENC","OK"], +["0 0 1","WITHIN","P2SH,STRICTENC","OK"], +["1 0 1","WITHIN NOT","P2SH,STRICTENC","OK"], +["0 -2147483647 2147483647","WITHIN","P2SH,STRICTENC","OK"], +["-1 -100 100","WITHIN","P2SH,STRICTENC","OK"], +["11 -100 100","WITHIN","P2SH,STRICTENC","OK"], +["-2147483647 -100 100","WITHIN NOT","P2SH,STRICTENC","OK"], +["2147483647 -100 100","WITHIN NOT","P2SH,STRICTENC","OK"], +["2147483647 2147483647 SUB","0 EQUAL","P2SH,STRICTENC","OK"], +["2147483647 DUP ADD","4294967294 EQUAL","P2SH,STRICTENC","OK",">32 bit EQUAL is valid"], +["2147483647 NEGATE DUP ADD","-4294967294 EQUAL","P2SH,STRICTENC","OK"], +["''","RIPEMD160 0x14 0x9c1185a5c5e9fc54612808977ee8f548b2258d31 EQUAL","P2SH,STRICTENC","OK"], +["'a'","RIPEMD160 0x14 0x0bdc9d2d256b3ee9daae347be6f4dc835a467ffe EQUAL","P2SH,STRICTENC","OK"], +["'abcdefghijklmnopqrstuvwxyz'","RIPEMD160 0x14 0xf71c27109c692c1b56bbdceb5b9d2865b3708dbc EQUAL","P2SH,STRICTENC","OK"], +["''","SHA1 0x14 0xda39a3ee5e6b4b0d3255bfef95601890afd80709 EQUAL","P2SH,STRICTENC","OK"], +["'a'","SHA1 0x14 0x86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 EQUAL","P2SH,STRICTENC","OK"], +["'abcdefghijklmnopqrstuvwxyz'","SHA1 0x14 0x32d10c7b8cf96570ca04ce37f2a19d84240d3a89 EQUAL","P2SH,STRICTENC","OK"], +["''","SHA256 0x20 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 EQUAL","P2SH,STRICTENC","OK"], +["'a'","SHA256 0x20 0xca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb EQUAL","P2SH,STRICTENC","OK"], +["'abcdefghijklmnopqrstuvwxyz'","SHA256 0x20 0x71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73 EQUAL","P2SH,STRICTENC","OK"], +["''","DUP HASH160 SWAP SHA256 RIPEMD160 EQUAL","P2SH,STRICTENC","OK"], +["''","DUP HASH256 SWAP SHA256 SHA256 EQUAL","P2SH,STRICTENC","OK"], +["''","NOP HASH160 0x14 0xb472a266d0bd89c13706a4132ccfb16f7c3b9fcb EQUAL","P2SH,STRICTENC","OK"], +["'a'","HASH160 NOP 0x14 0x994355199e516ff76c4fa4aab39337b9d84cf12b EQUAL","P2SH,STRICTENC","OK"], +["'abcdefghijklmnopqrstuvwxyz'","HASH160 0x4c 0x14 0xc286a1af0947f58d1ad787385b1c2c4a976f9e71 EQUAL","P2SH,STRICTENC","OK"], +["''","HASH256 0x20 0x5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456 EQUAL","P2SH,STRICTENC","OK"], +["'a'","HASH256 0x20 0xbf5d3affb73efd2ec6c36ad3112dd933efed63c4e1cbffcfa88e2759c144f2d8 EQUAL","P2SH,STRICTENC","OK"], +["'abcdefghijklmnopqrstuvwxyz'","HASH256 0x4c 0x20 0xca139bc10c2f660da42666f72e89a225936fc60f193c161124a672050c434671 EQUAL","P2SH,STRICTENC","OK"], +["1","NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 1 EQUAL","P2SH,STRICTENC","OK"], +["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_10' EQUAL","P2SH,STRICTENC","OK"], +["1","NOP","P2SH,STRICTENC,DISCOURAGE_UPGRADABLE_NOPS","OK","Discourage NOPx flag allows OP_NOP"], +["0","IF NOP10 ENDIF 1","P2SH,STRICTENC,DISCOURAGE_UPGRADABLE_NOPS","OK","Discouraged NOPs are allowed if not executed"], +["0","IF 0xba ELSE 1 ENDIF","P2SH,STRICTENC","OK","opcodes above MAX_OPCODE invalid if executed"], +["0","IF 0xbb ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xbc ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xbd ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xbe ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xbf ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xc0 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xc1 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xc2 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xc3 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xc4 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xc5 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xc6 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xc7 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xc8 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xc9 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xca ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xcb ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xcc ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xcd ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xce ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xcf ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xd0 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xd1 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xd2 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xd3 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xd4 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xd5 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xd6 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xd7 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xd8 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xd9 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xda ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xdb ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xdc ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xdd ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xde ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xdf ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xe0 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xe1 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xe2 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xe3 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xe4 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xe5 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xe6 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xe7 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xe8 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xe9 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xea ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xeb ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xec ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xed ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xee ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xef ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xf0 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xf1 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xf2 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xf3 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xf4 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xf5 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xf6 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xf7 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xf8 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xf9 ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xfa ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xfb ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xfc ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xfd ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xfe ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["0","IF 0xff ELSE 1 ENDIF","P2SH,STRICTENC","OK"], +["NOP","'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'","P2SH,STRICTENC","OK","520 byte push"], +["1","0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161","P2SH,STRICTENC","OK","201 opcodes executed. 0x61 is NOP"], +["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f","1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f","P2SH,STRICTENC","OK","1,000 stack size (0x6f is 3DUP)"], +["1 TOALTSTACK 2 TOALTSTACK 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f","1 2 3 4 5 6 7 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f","P2SH,STRICTENC","OK","1,000 stack size (altstack cleared between scriptSig/scriptPubKey)"], +["'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f","'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f 2DUP 0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161","P2SH,STRICTENC","OK","Max-size (10,000-byte), max-push(520 bytes), max-opcodes(201), max stack size(1,000 items). 0x6f is 3DUP, 0x61 is NOP"], +["0","IF 0x5050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050 ENDIF 1","P2SH,STRICTENC","OK",">201 opcodes, but RESERVED (0x50) doesn't count towards opcode limit."], +["NOP","1","P2SH,STRICTENC","OK"], +["1","0x01 0x01 EQUAL","P2SH,STRICTENC","OK","The following is useful for checking implementations of BN_bn2mpi"], +["127","0x01 0x7F EQUAL","P2SH,STRICTENC","OK"], +["128","0x02 0x8000 EQUAL","P2SH,STRICTENC","OK","Leave room for the sign bit"], +["32767","0x02 0xFF7F EQUAL","P2SH,STRICTENC","OK"], +["32768","0x03 0x008000 EQUAL","P2SH,STRICTENC","OK"], +["8388607","0x03 0xFFFF7F EQUAL","P2SH,STRICTENC","OK"], +["8388608","0x04 0x00008000 EQUAL","P2SH,STRICTENC","OK"], +["2147483647","0x04 0xFFFFFF7F EQUAL","P2SH,STRICTENC","OK"], +["2147483648","0x05 0x0000008000 EQUAL","P2SH,STRICTENC","OK"], +["0x05ffffffff7f","0x05 0xFFFFFFFF7F EQUAL","P2SH,STRICTENC","OK"], +["0x06000000008000","0x06 0x000000008000 EQUAL","P2SH,STRICTENC","OK"], +["0x08ffffffffffffff7f","0x08 0xFFFFFFFFFFFFFF7F EQUAL","P2SH,STRICTENC","OK"], +["-1","0x01 0x81 EQUAL","P2SH,STRICTENC","OK","Numbers are little-endian with the MSB being a sign bit"], +["-127","0x01 0xFF EQUAL","P2SH,STRICTENC","OK"], +["-128","0x02 0x8080 EQUAL","P2SH,STRICTENC","OK"], +["-32767","0x02 0xFFFF EQUAL","P2SH,STRICTENC","OK"], +["-32768","0x03 0x008080 EQUAL","P2SH,STRICTENC","OK"], +["-8388607","0x03 0xFFFFFF EQUAL","P2SH,STRICTENC","OK"], +["-8388608","0x04 0x00008080 EQUAL","P2SH,STRICTENC","OK"], +["-2147483647","0x04 0xFFFFFFFF EQUAL","P2SH,STRICTENC","OK"], +["-2147483648","0x05 0x0000008080 EQUAL","P2SH,STRICTENC","OK"], +["-4294967295","0x05 0xFFFFFFFF80 EQUAL","P2SH,STRICTENC","OK"], +["0x05ffffffffff","0x05 0xFFFFFFFFFF EQUAL","P2SH,STRICTENC","OK"], +["0x06000000008080","0x06 0x000000008080 EQUAL","P2SH,STRICTENC","OK"], +["0x08ffffffffffffffff","0x08 0xFFFFFFFFFFFFFFFF EQUAL","P2SH,STRICTENC","OK"], +["2147483647","1ADD 2147483648 EQUAL","P2SH,STRICTENC","OK","We can do math on 4-byte integers, and compare 5-byte ones"], +["2147483647","1ADD 1","P2SH,STRICTENC","OK"], +["-2147483647","1ADD 1","P2SH,STRICTENC","OK"], +["1","0x02 0x0100 EQUAL NOT","P2SH,STRICTENC","OK","Not the same byte array..."], +["1","0x02 0x0100 NUMEQUAL","P2SH,STRICTENC","OK","... but they are numerically equal"], +["11","0x4c 0x03 0x0b0000 NUMEQUAL","P2SH,STRICTENC","OK"], +["0","0x01 0x80 EQUAL NOT","P2SH,STRICTENC","OK"], +["0","0x01 0x80 NUMEQUAL","P2SH,STRICTENC","OK","Zero numerically equals negative zero"], +["0","0x02 0x0080 NUMEQUAL","P2SH,STRICTENC","OK"], +["0x03 0x000080","0x04 0x00000080 NUMEQUAL","P2SH,STRICTENC","OK"], +["0x03 0x100080","0x04 0x10000080 NUMEQUAL","P2SH,STRICTENC","OK"], +["0x03 0x100000","0x04 0x10000000 NUMEQUAL","P2SH,STRICTENC","OK"], +["NOP","NOP 1","P2SH,STRICTENC","OK","The following tests check the if(stack.size() < N) tests in each opcode"], +["1","IF 1 ENDIF","P2SH,STRICTENC","OK","They are here to catch copy-and-paste errors"], +["0","NOTIF 1 ENDIF","P2SH,STRICTENC","OK","Most of them are duplicated elsewhere,"], +["1","VERIFY 1","P2SH,STRICTENC","OK","but, hey, more is always better, right?"], +["0","TOALTSTACK 1","P2SH,STRICTENC","OK"], +["1","TOALTSTACK FROMALTSTACK","P2SH,STRICTENC","OK"], +["0 0","2DROP 1","P2SH,STRICTENC","OK"], +["0 1","2DUP","P2SH,STRICTENC","OK"], +["0 0 1","3DUP","P2SH,STRICTENC","OK"], +["0 1 0 0","2OVER","P2SH,STRICTENC","OK"], +["0 1 0 0 0 0","2ROT","P2SH,STRICTENC","OK"], +["0 1 0 0","2SWAP","P2SH,STRICTENC","OK"], +["1","IFDUP","P2SH,STRICTENC","OK"], +["NOP","DEPTH 1","P2SH,STRICTENC","OK"], +["0","DROP 1","P2SH,STRICTENC","OK"], +["1","DUP","P2SH,STRICTENC","OK"], +["0 1","NIP","P2SH,STRICTENC","OK"], +["1 0","OVER","P2SH,STRICTENC","OK"], +["1 0 0 0 3","PICK","P2SH,STRICTENC","OK"], +["1 0","PICK","P2SH,STRICTENC","OK"], +["1 0 0 0 3","ROLL","P2SH,STRICTENC","OK"], +["1 0","ROLL","P2SH,STRICTENC","OK"], +["1 0 0","ROT","P2SH,STRICTENC","OK"], +["1 0","SWAP","P2SH,STRICTENC","OK"], +["0 1","TUCK","P2SH,STRICTENC","OK"], +["1","SIZE","P2SH,STRICTENC","OK"], +["0 0","EQUAL","P2SH,STRICTENC","OK"], +["0 0","EQUALVERIFY 1","P2SH,STRICTENC","OK"], +["0 0 1","EQUAL EQUAL","P2SH,STRICTENC","OK","OP_0 and bools must have identical byte representations"], +["0","1ADD","P2SH,STRICTENC","OK"], +["2","1SUB","P2SH,STRICTENC","OK"], +["-1","NEGATE","P2SH,STRICTENC","OK"], +["-1","ABS","P2SH,STRICTENC","OK"], +["0","NOT","P2SH,STRICTENC","OK"], +["-1","0NOTEQUAL","P2SH,STRICTENC","OK"], +["1 0","ADD","P2SH,STRICTENC","OK"], +["1 0","SUB","P2SH,STRICTENC","OK"], +["-1 -1","BOOLAND","P2SH,STRICTENC","OK"], +["-1 0","BOOLOR","P2SH,STRICTENC","OK"], +["0 0","NUMEQUAL","P2SH,STRICTENC","OK"], +["0 0","NUMEQUALVERIFY 1","P2SH,STRICTENC","OK"], +["-1 0","NUMNOTEQUAL","P2SH,STRICTENC","OK"], +["-1 0","LESSTHAN","P2SH,STRICTENC","OK"], +["1 0","GREATERTHAN","P2SH,STRICTENC","OK"], +["0 0","LESSTHANOREQUAL","P2SH,STRICTENC","OK"], +["0 0","GREATERTHANOREQUAL","P2SH,STRICTENC","OK"], +["-1 0","MIN","P2SH,STRICTENC","OK"], +["1 0","MAX","P2SH,STRICTENC","OK"], +["-1 -1 0","WITHIN","P2SH,STRICTENC","OK"], +["0","RIPEMD160","P2SH,STRICTENC","OK"], +["0","SHA1","P2SH,STRICTENC","OK"], +["0","SHA256","P2SH,STRICTENC","OK"], +["0","HASH160","P2SH,STRICTENC","OK"], +["0","HASH256","P2SH,STRICTENC","OK"], +["NOP","CODESEPARATOR 1","P2SH,STRICTENC","OK"], +["NOP","NOP1 1","P2SH,STRICTENC","OK"], +["NOP","CHECKLOCKTIMEVERIFY 1","P2SH,STRICTENC","OK"], +["NOP","CHECKSEQUENCEVERIFY 1","P2SH,STRICTENC","OK"], +["NOP","NOP4 1","P2SH,STRICTENC","OK"], +["NOP","NOP5 1","P2SH,STRICTENC","OK"], +["NOP","NOP6 1","P2SH,STRICTENC","OK"], +["NOP","NOP7 1","P2SH,STRICTENC","OK"], +["NOP","NOP8 1","P2SH,STRICTENC","OK"], +["NOP","NOP9 1","P2SH,STRICTENC","OK"], +["NOP","NOP10 1","P2SH,STRICTENC","OK"], +["","0 0 0 CHECKMULTISIG VERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK","CHECKMULTISIG is allowed to have zero keys and/or sigs"], +["","0 0 0 CHECKMULTISIGVERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 0 1 CHECKMULTISIG VERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK","Zero sigs means no sigs are checked"], +["","0 0 0 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 0 CHECKMULTISIG VERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK","CHECKMULTISIG is allowed to have zero keys and/or sigs"], +["","0 0 0 CHECKMULTISIGVERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 0 1 CHECKMULTISIG VERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK","Zero sigs means no sigs are checked"], +["","0 0 0 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 2 CHECKMULTISIG VERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK","Test from up to 20 pubkeys, all not checked"], +["","0 0 'a' 'b' 'c' 3 CHECKMULTISIG VERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 4 CHECKMULTISIG VERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 5 CHECKMULTISIG VERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 6 CHECKMULTISIG VERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 7 CHECKMULTISIG VERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 8 CHECKMULTISIG VERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 9 CHECKMULTISIG VERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 10 CHECKMULTISIG VERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 11 CHECKMULTISIG VERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 12 CHECKMULTISIG VERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 13 CHECKMULTISIG VERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 14 CHECKMULTISIG VERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 15 CHECKMULTISIG VERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 16 CHECKMULTISIG VERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 17 CHECKMULTISIG VERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 18 CHECKMULTISIG VERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 19 CHECKMULTISIG VERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG VERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 2 CHECKMULTISIGVERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 3 CHECKMULTISIGVERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 4 CHECKMULTISIGVERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 5 CHECKMULTISIGVERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 6 CHECKMULTISIGVERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 7 CHECKMULTISIGVERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 8 CHECKMULTISIGVERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 9 CHECKMULTISIGVERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 10 CHECKMULTISIGVERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 11 CHECKMULTISIGVERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 12 CHECKMULTISIGVERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 13 CHECKMULTISIGVERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 14 CHECKMULTISIGVERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 15 CHECKMULTISIGVERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 16 CHECKMULTISIGVERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 17 CHECKMULTISIGVERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 18 CHECKMULTISIGVERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 19 CHECKMULTISIGVERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY DEPTH 0 EQUAL","P2SH,STRICTENC","OK"], +["","0 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG","P2SH,STRICTENC","OK","nOpCount is incremented by the number of keys evaluated in addition to the usual one op per op. In this case we have zero keys, so we can execute 201 CHECKMULTISIGS"], +["1","0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY","P2SH,STRICTENC","OK"], +["","NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG","P2SH,STRICTENC","OK","Even though there are no signatures being checked nOpCount is incremented by the number of keys."], +["1","NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY","P2SH,STRICTENC","OK"], +["0 0x01 1","HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL","P2SH,STRICTENC","OK","Very basic P2SH"], +["0x4c 0 0x01 1","HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL","P2SH,STRICTENC","OK"], +["0x40 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242","0x4d 0x4000 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242 EQUAL","P2SH,STRICTENC","OK","Basic PUSH signedness check"], +["0x4c 0x40 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242","0x4d 0x4000 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242 EQUAL","P2SH,STRICTENC","OK","Basic PUSHDATA1 signedness check"], +["0x4c 0x4b 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111","0x4b 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 EQUAL","","OK","PUSHDATA1 of 75 bytes equals direct push of it"], +["0x4d 0xFF00 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111","0x4c 0xFF 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 EQUAL","","OK","PUSHDATA2 of 255 bytes equals PUSHDATA1 of it"], +["0x00","SIZE 0 EQUAL","P2SH,STRICTENC","OK","Basic OP_0 execution"], +["0x01 0x81","0x4f EQUAL","","OK","OP1_NEGATE pushes 0x81"], +["0x01 0x01","0x51 EQUAL","","OK","OP_1 pushes 0x01"], +["0x01 0x02","0x52 EQUAL","","OK","OP_2 pushes 0x02"], +["0x01 0x03","0x53 EQUAL","","OK","OP_3 pushes 0x03"], +["0x01 0x04","0x54 EQUAL","","OK","OP_4 pushes 0x04"], +["0x01 0x05","0x55 EQUAL","","OK","OP_5 pushes 0x05"], +["0x01 0x06","0x56 EQUAL","","OK","OP_6 pushes 0x06"], +["0x01 0x07","0x57 EQUAL","","OK","OP_7 pushes 0x07"], +["0x01 0x08","0x58 EQUAL","","OK","OP_8 pushes 0x08"], +["0x01 0x09","0x59 EQUAL","","OK","OP_9 pushes 0x09"], +["0x01 0x0a","0x5a EQUAL","","OK","OP_10 pushes 0x0a"], +["0x01 0x0b","0x5b EQUAL","","OK","OP_11 pushes 0x0b"], +["0x01 0x0c","0x5c EQUAL","","OK","OP_12 pushes 0x0c"], +["0x01 0x0d","0x5d EQUAL","","OK","OP_13 pushes 0x0d"], +["0x01 0x0e","0x5e EQUAL","","OK","OP_14 pushes 0x0e"], +["0x01 0x0f","0x5f EQUAL","","OK","OP_15 pushes 0x0f"], +["0x01 0x10","0x60 EQUAL","","OK","OP_16 pushes 0x10"], +["0x02 0x8000","128 NUMEQUAL","","OK","0x8000 equals 128"], +["0x01 0x00","0 NUMEQUAL","","OK","0x00 numequals 0"], +["0x01 0x80","0 NUMEQUAL","","OK","0x80 (negative zero) numequals 0"], +["0x02 0x0080","0 NUMEQUAL","","OK","0x0080 numequals 0"], +["0x02 0x0500","5 NUMEQUAL","","OK","0x0500 numequals 5"], +["0x03 0xff7f80","0x02 0xffff NUMEQUAL","","OK",""], +["0x03 0xff7f00","0x02 0xff7f NUMEQUAL","","OK",""], +["0x04 0xffff7f80","0x03 0xffffff NUMEQUAL","","OK",""], +["0x04 0xffff7f00","0x03 0xffff7f NUMEQUAL","","OK",""], +["0 IF 0x4c 0x00 ENDIF 1","","MINIMALDATA","OK","non-minimal PUSHDATA1 ignored"], +["0 IF 0x4d 0x0000 ENDIF 1","","MINIMALDATA","OK","non-minimal PUSHDATA2 ignored"], +["0 IF 0x4c 0x00000000 ENDIF 1","","MINIMALDATA","OK","non-minimal PUSHDATA4 ignored"], +["0 IF 0x01 0x81 ENDIF 1","","MINIMALDATA","OK","1NEGATE equiv"], +["0 IF 0x01 0x01 ENDIF 1","","MINIMALDATA","OK","OP_1 equiv"], +["0 IF 0x01 0x02 ENDIF 1","","MINIMALDATA","OK","OP_2 equiv"], +["0 IF 0x01 0x03 ENDIF 1","","MINIMALDATA","OK","OP_3 equiv"], +["0 IF 0x01 0x04 ENDIF 1","","MINIMALDATA","OK","OP_4 equiv"], +["0 IF 0x01 0x05 ENDIF 1","","MINIMALDATA","OK","OP_5 equiv"], +["0 IF 0x01 0x06 ENDIF 1","","MINIMALDATA","OK","OP_6 equiv"], +["0 IF 0x01 0x07 ENDIF 1","","MINIMALDATA","OK","OP_7 equiv"], +["0 IF 0x01 0x08 ENDIF 1","","MINIMALDATA","OK","OP_8 equiv"], +["0 IF 0x01 0x09 ENDIF 1","","MINIMALDATA","OK","OP_9 equiv"], +["0 IF 0x01 0x0a ENDIF 1","","MINIMALDATA","OK","OP_10 equiv"], +["0 IF 0x01 0x0b ENDIF 1","","MINIMALDATA","OK","OP_11 equiv"], +["0 IF 0x01 0x0c ENDIF 1","","MINIMALDATA","OK","OP_12 equiv"], +["0 IF 0x01 0x0d ENDIF 1","","MINIMALDATA","OK","OP_13 equiv"], +["0 IF 0x01 0x0e ENDIF 1","","MINIMALDATA","OK","OP_14 equiv"], +["0 IF 0x01 0x0f ENDIF 1","","MINIMALDATA","OK","OP_15 equiv"], +["0 IF 0x01 0x10 ENDIF 1","","MINIMALDATA","OK","OP_16 equiv"], +["0x01 0x00","1","MINIMALDATA","OK"], +["0x01 0x80","1","MINIMALDATA","OK"], +["0x02 0x0180","1","MINIMALDATA","OK"], +["0x02 0x0100","1","MINIMALDATA","OK"], +["0x02 0x0200","1","MINIMALDATA","OK"], +["0x02 0x0300","1","MINIMALDATA","OK"], +["0x02 0x0400","1","MINIMALDATA","OK"], +["0x02 0x0500","1","MINIMALDATA","OK"], +["0x02 0x0600","1","MINIMALDATA","OK"], +["0x02 0x0700","1","MINIMALDATA","OK"], +["0x02 0x0800","1","MINIMALDATA","OK"], +["0x02 0x0900","1","MINIMALDATA","OK"], +["0x02 0x0a00","1","MINIMALDATA","OK"], +["0x02 0x0b00","1","MINIMALDATA","OK"], +["0x02 0x0c00","1","MINIMALDATA","OK"], +["0x02 0x0d00","1","MINIMALDATA","OK"], +["0x02 0x0e00","1","MINIMALDATA","OK"], +["0x02 0x0f00","1","MINIMALDATA","OK"], +["0x02 0x1000","1","MINIMALDATA","OK"], +["1 0x02 0x0000","PICK DROP","","OK"], +["1 0x02 0x0000","ROLL DROP 1","","OK"], +["0x02 0x0000","1ADD DROP 1","","OK"], +["0x02 0x0000","1SUB DROP 1","","OK"], +["0x02 0x0000","NEGATE DROP 1","","OK"], +["0x02 0x0000","ABS DROP 1","","OK"], +["0x02 0x0000","NOT DROP 1","","OK"], +["0x02 0x0000","0NOTEQUAL DROP 1","","OK"], +["0 0x02 0x0000","ADD DROP 1","","OK"], +["0x02 0x0000 0","ADD DROP 1","","OK"], +["0 0x02 0x0000","SUB DROP 1","","OK"], +["0x02 0x0000 0","SUB DROP 1","","OK"], +["0 0x02 0x0000","BOOLAND DROP 1","","OK"], +["0x02 0x0000 0","BOOLAND DROP 1","","OK"], +["0 0x02 0x0000","BOOLOR DROP 1","","OK"], +["0x02 0x0000 0","BOOLOR DROP 1","","OK"], +["0 0x02 0x0000","NUMEQUAL DROP 1","","OK"], +["0x02 0x0000 1","NUMEQUAL DROP 1","","OK"], +["0 0x02 0x0000","NUMEQUALVERIFY 1","","OK"], +["0x02 0x0000 0","NUMEQUALVERIFY 1","","OK"], +["0 0x02 0x0000","NUMNOTEQUAL DROP 1","","OK"], +["0x02 0x0000 0","NUMNOTEQUAL DROP 1","","OK"], +["0 0x02 0x0000","LESSTHAN DROP 1","","OK"], +["0x02 0x0000 0","LESSTHAN DROP 1","","OK"], +["0 0x02 0x0000","GREATERTHAN DROP 1","","OK"], +["0x02 0x0000 0","GREATERTHAN DROP 1","","OK"], +["0 0x02 0x0000","LESSTHANOREQUAL DROP 1","","OK"], +["0x02 0x0000 0","LESSTHANOREQUAL DROP 1","","OK"], +["0 0x02 0x0000","GREATERTHANOREQUAL DROP 1","","OK"], +["0x02 0x0000 0","GREATERTHANOREQUAL DROP 1","","OK"], +["0 0x02 0x0000","MIN DROP 1","","OK"], +["0x02 0x0000 0","MIN DROP 1","","OK"], +["0 0x02 0x0000","MAX DROP 1","","OK"], +["0x02 0x0000 0","MAX DROP 1","","OK"], +["0x02 0x0000 0 0","WITHIN DROP 1","","OK"], +["0 0x02 0x0000 0","WITHIN DROP 1","","OK"], +["0 0 0x02 0x0000","WITHIN DROP 1","","OK"], +["0 0 0x02 0x0000","CHECKMULTISIG DROP 1","","OK"], +["0 0x02 0x0000 0","CHECKMULTISIG DROP 1","","OK"], +["0 0x02 0x0000 0 1","CHECKMULTISIG DROP 1","","OK"], +["0 0 0x02 0x0000","CHECKMULTISIGVERIFY 1","","OK"], +["0 0x02 0x0000 0","CHECKMULTISIGVERIFY 1","","OK"], +["0","0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 CHECKSIG NOT","STRICTENC","OK"], +["0 0","1 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 1 CHECKMULTISIG NOT","STRICTENC","OK"], +["0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501","2 0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT","STRICTENC","OK","2-of-2 CHECKMULTISIG NOT with the second pubkey invalid, and both signatures validly encoded. Valid pubkey fails, and CHECKMULTISIG exits early, prior to evaluation of second invalid pubkey."], +["0 0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501","2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT","STRICTENC","OK","2-of-2 CHECKMULTISIG NOT with both pubkeys valid, but second signature invalid. Valid pubkey fails, and CHECKMULTISIG exits early, prior to evaluation of second invalid signature."], +["0x4a 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","0 CHECKSIG NOT","","OK","Overly long signature is correctly encoded"], +["0x25 0x30220220000000000000000000000000000000000000000000000000000000000000000000","0 CHECKSIG NOT","","OK","Missing S is correctly encoded"], +["0x27 0x3024021077777777777777777777777777777777020a7777777777777777777777777777777701","0 CHECKSIG NOT","","OK","S with invalid S length is correctly encoded"], +["0x27 0x302403107777777777777777777777777777777702107777777777777777777777777777777701","0 CHECKSIG NOT","","OK","Non-integer R is correctly encoded"], +["0x27 0x302402107777777777777777777777777777777703107777777777777777777777777777777701","0 CHECKSIG NOT","","OK","Non-integer S is correctly encoded"], +["0x17 0x3014020002107777777777777777777777777777777701","0 CHECKSIG NOT","","OK","Zero-length R is correctly encoded"], +["0x17 0x3014021077777777777777777777777777777777020001","0 CHECKSIG NOT","","OK","Zero-length S is correctly encoded for DERSIG"], +["0x27 0x302402107777777777777777777777777777777702108777777777777777777777777777777701","0 CHECKSIG NOT","","OK","Negative S is correctly encoded"], +["2147483648","CHECKSEQUENCEVERIFY","CHECKSEQUENCEVERIFY","OK","CSV passes if stack top bit 1 << 31 is set"], +["","DEPTH","P2SH,STRICTENC","EVAL_FALSE","Test the test: we should have an empty stack after scriptSig evaluation"], +[" ","DEPTH","P2SH,STRICTENC","EVAL_FALSE","and multiple spaces should not change that."], +[" ","DEPTH","P2SH,STRICTENC","EVAL_FALSE"], +[" ","DEPTH","P2SH,STRICTENC","EVAL_FALSE"], +["","","P2SH,STRICTENC","EVAL_FALSE"], +["","NOP","P2SH,STRICTENC","EVAL_FALSE"], +["","NOP DEPTH","P2SH,STRICTENC","EVAL_FALSE"], +["NOP","","P2SH,STRICTENC","EVAL_FALSE"], +["NOP","DEPTH","P2SH,STRICTENC","EVAL_FALSE"], +["NOP","NOP","P2SH,STRICTENC","EVAL_FALSE"], +["NOP","NOP DEPTH","P2SH,STRICTENC","EVAL_FALSE"], +["DEPTH","","P2SH,STRICTENC","EVAL_FALSE"], +["0x4c01","0x01 NOP","P2SH,STRICTENC","BAD_OPCODE","PUSHDATA1 with not enough bytes"], +["0x4d0200ff","0x01 NOP","P2SH,STRICTENC","BAD_OPCODE","PUSHDATA2 with not enough bytes"], +["0x4e03000000ffff","0x01 NOP","P2SH,STRICTENC","BAD_OPCODE","PUSHDATA4 with not enough bytes"], +["1","IF 0x50 ENDIF 1","P2SH,STRICTENC","BAD_OPCODE","0x50 is reserved"], +["0x52","0x5f ADD 0x60 EQUAL","P2SH,STRICTENC","EVAL_FALSE","0x51 through 0x60 push 1 through 16 onto stack"], +["0","NOP","P2SH,STRICTENC","EVAL_FALSE",""], +["1","IF VER ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE","VER non-functional"], +["0","IF VERIF ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE","VERIF illegal everywhere"], +["0","IF ELSE 1 ELSE VERIF ENDIF","P2SH,STRICTENC","BAD_OPCODE","VERIF illegal everywhere"], +["0","IF VERNOTIF ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE","VERNOTIF illegal everywhere"], +["0","IF ELSE 1 ELSE VERNOTIF ENDIF","P2SH,STRICTENC","BAD_OPCODE","VERNOTIF illegal everywhere"], +["1 IF","1 ENDIF","P2SH,STRICTENC","UNBALANCED_CONDITIONAL","IF/ENDIF can't span scriptSig/scriptPubKey"], +["1 IF 0 ENDIF","1 ENDIF","P2SH,STRICTENC","UNBALANCED_CONDITIONAL"], +["1 ELSE 0 ENDIF","1","P2SH,STRICTENC","UNBALANCED_CONDITIONAL"], +["0 NOTIF","123","P2SH,STRICTENC","UNBALANCED_CONDITIONAL"], +["0","DUP IF ENDIF","P2SH,STRICTENC","EVAL_FALSE"], +["0","IF 1 ENDIF","P2SH,STRICTENC","EVAL_FALSE"], +["0","DUP IF ELSE ENDIF","P2SH,STRICTENC","EVAL_FALSE"], +["0","IF 1 ELSE ENDIF","P2SH,STRICTENC","EVAL_FALSE"], +["0","NOTIF ELSE 1 ENDIF","P2SH,STRICTENC","EVAL_FALSE"], +["0 1","IF IF 1 ELSE 0 ENDIF ENDIF","P2SH,STRICTENC","EVAL_FALSE"], +["0 0","IF IF 1 ELSE 0 ENDIF ENDIF","P2SH,STRICTENC","EVAL_FALSE"], +["1 0","IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF","P2SH,STRICTENC","EVAL_FALSE"], +["0 1","IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF","P2SH,STRICTENC","EVAL_FALSE"], +["0 0","NOTIF IF 1 ELSE 0 ENDIF ENDIF","P2SH,STRICTENC","EVAL_FALSE"], +["0 1","NOTIF IF 1 ELSE 0 ENDIF ENDIF","P2SH,STRICTENC","EVAL_FALSE"], +["1 1","NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF","P2SH,STRICTENC","EVAL_FALSE"], +["0 0","NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF","P2SH,STRICTENC","EVAL_FALSE"], +["1","IF RETURN ELSE ELSE 1 ENDIF","P2SH,STRICTENC","OP_RETURN","Multiple ELSEs"], +["1","IF 1 ELSE ELSE RETURN ENDIF","P2SH,STRICTENC","OP_RETURN"], +["1","ENDIF","P2SH,STRICTENC","UNBALANCED_CONDITIONAL","Malformed IF/ELSE/ENDIF sequence"], +["1","ELSE ENDIF","P2SH,STRICTENC","UNBALANCED_CONDITIONAL"], +["1","ENDIF ELSE","P2SH,STRICTENC","UNBALANCED_CONDITIONAL"], +["1","ENDIF ELSE IF","P2SH,STRICTENC","UNBALANCED_CONDITIONAL"], +["1","IF ELSE ENDIF ELSE","P2SH,STRICTENC","UNBALANCED_CONDITIONAL"], +["1","IF ELSE ENDIF ELSE ENDIF","P2SH,STRICTENC","UNBALANCED_CONDITIONAL"], +["1","IF ENDIF ENDIF","P2SH,STRICTENC","UNBALANCED_CONDITIONAL"], +["1","IF ELSE ELSE ENDIF ENDIF","P2SH,STRICTENC","UNBALANCED_CONDITIONAL"], +["1","RETURN","P2SH,STRICTENC","OP_RETURN"], +["1","DUP IF RETURN ENDIF","P2SH,STRICTENC","OP_RETURN"], +["1","RETURN 'data'","P2SH,STRICTENC","OP_RETURN","canonical prunable txout format"], +["0 IF","RETURN ENDIF 1","P2SH,STRICTENC","UNBALANCED_CONDITIONAL","still prunable because IF/ENDIF can't span scriptSig/scriptPubKey"], +["0","VERIFY 1","P2SH,STRICTENC","VERIFY"], +["1","VERIFY","P2SH,STRICTENC","EVAL_FALSE"], +["1","VERIFY 0","P2SH,STRICTENC","EVAL_FALSE"], +["1 TOALTSTACK","FROMALTSTACK 1","P2SH,STRICTENC","INVALID_ALTSTACK_OPERATION","alt stack not shared between sig/pubkey"], +["IFDUP","DEPTH 0 EQUAL","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["DROP","DEPTH 0 EQUAL","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["DUP","DEPTH 0 EQUAL","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","DUP 1 ADD 2 EQUALVERIFY 0 EQUAL","P2SH,STRICTENC","EVAL_FALSE"], +["NOP","NIP","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","1 NIP","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","1 0 NIP","P2SH,STRICTENC","EVAL_FALSE"], +["NOP","OVER 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","OVER","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["0 1","OVER DEPTH 3 EQUALVERIFY","P2SH,STRICTENC","EVAL_FALSE"], +["19 20 21","PICK 19 EQUALVERIFY DEPTH 2 EQUAL","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","0 PICK","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","-1 PICK","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["19 20 21","0 PICK 20 EQUALVERIFY DEPTH 3 EQUAL","P2SH,STRICTENC","EQUALVERIFY"], +["19 20 21","1 PICK 21 EQUALVERIFY DEPTH 3 EQUAL","P2SH,STRICTENC","EQUALVERIFY"], +["19 20 21","2 PICK 22 EQUALVERIFY DEPTH 3 EQUAL","P2SH,STRICTENC","EQUALVERIFY"], +["NOP","0 ROLL","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","-1 ROLL","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["19 20 21","0 ROLL 20 EQUALVERIFY DEPTH 2 EQUAL","P2SH,STRICTENC","EQUALVERIFY"], +["19 20 21","1 ROLL 21 EQUALVERIFY DEPTH 2 EQUAL","P2SH,STRICTENC","EQUALVERIFY"], +["19 20 21","2 ROLL 22 EQUALVERIFY DEPTH 2 EQUAL","P2SH,STRICTENC","EQUALVERIFY"], +["NOP","ROT 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","1 ROT 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","1 2 ROT 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","0 1 2 ROT","P2SH,STRICTENC","EVAL_FALSE"], +["NOP","SWAP 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","SWAP 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["0 1","SWAP 1 EQUALVERIFY","P2SH,STRICTENC","EQUALVERIFY"], +["NOP","TUCK 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","TUCK 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1 0","TUCK DEPTH 3 EQUALVERIFY SWAP 2DROP","P2SH,STRICTENC","EVAL_FALSE"], +["NOP","2DUP 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","2DUP 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","3DUP 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","3DUP 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1 2","3DUP 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","2OVER 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","2 3 2OVER 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","2SWAP 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","2 3 2SWAP 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","SIZE 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["'a' 'b'","CAT","P2SH,STRICTENC","DISABLED_OPCODE","CAT disabled"], +["'a' 'b' 0","IF CAT ELSE 1 ENDIF","P2SH,STRICTENC","DISABLED_OPCODE","CAT disabled"], +["'abc' 1 1","SUBSTR","P2SH,STRICTENC","DISABLED_OPCODE","SUBSTR disabled"], +["'abc' 1 1 0","IF SUBSTR ELSE 1 ENDIF","P2SH,STRICTENC","DISABLED_OPCODE","SUBSTR disabled"], +["'abc' 2 0","IF LEFT ELSE 1 ENDIF","P2SH,STRICTENC","DISABLED_OPCODE","LEFT disabled"], +["'abc' 2 0","IF RIGHT ELSE 1 ENDIF","P2SH,STRICTENC","DISABLED_OPCODE","RIGHT disabled"], +["'abc'","IF INVERT ELSE 1 ENDIF","P2SH,STRICTENC","DISABLED_OPCODE","INVERT disabled"], +["1 2 0 IF AND ELSE 1 ENDIF","NOP","P2SH,STRICTENC","DISABLED_OPCODE","AND disabled"], +["1 2 0 IF OR ELSE 1 ENDIF","NOP","P2SH,STRICTENC","DISABLED_OPCODE","OR disabled"], +["1 2 0 IF XOR ELSE 1 ENDIF","NOP","P2SH,STRICTENC","DISABLED_OPCODE","XOR disabled"], +["2 0 IF 2MUL ELSE 1 ENDIF","NOP","P2SH,STRICTENC","DISABLED_OPCODE","2MUL disabled"], +["2 0 IF 2DIV ELSE 1 ENDIF","NOP","P2SH,STRICTENC","DISABLED_OPCODE","2DIV disabled"], +["2 2 0 IF MUL ELSE 1 ENDIF","NOP","P2SH,STRICTENC","DISABLED_OPCODE","MUL disabled"], +["2 2 0 IF DIV ELSE 1 ENDIF","NOP","P2SH,STRICTENC","DISABLED_OPCODE","DIV disabled"], +["2 2 0 IF MOD ELSE 1 ENDIF","NOP","P2SH,STRICTENC","DISABLED_OPCODE","MOD disabled"], +["2 2 0 IF LSHIFT ELSE 1 ENDIF","NOP","P2SH,STRICTENC","DISABLED_OPCODE","LSHIFT disabled"], +["2 2 0 IF RSHIFT ELSE 1 ENDIF","NOP","P2SH,STRICTENC","DISABLED_OPCODE","RSHIFT disabled"], +["","EQUAL NOT","P2SH,STRICTENC","INVALID_STACK_OPERATION","EQUAL must error when there are no stack items"], +["0","EQUAL NOT","P2SH,STRICTENC","INVALID_STACK_OPERATION","EQUAL must error when there are not 2 stack items"], +["0 1","EQUAL","P2SH,STRICTENC","EVAL_FALSE"], +["1 1 ADD","0 EQUAL","P2SH,STRICTENC","EVAL_FALSE"], +["11 1 ADD 12 SUB","11 EQUAL","P2SH,STRICTENC","EVAL_FALSE"], +["2147483648 0 ADD","NOP","P2SH,STRICTENC","UNKNOWN_ERROR","arithmetic operands must be in range [-2^31...2^31] "], +["-2147483648 0 ADD","NOP","P2SH,STRICTENC","UNKNOWN_ERROR","arithmetic operands must be in range [-2^31...2^31] "], +["2147483647 DUP ADD","4294967294 NUMEQUAL","P2SH,STRICTENC","UNKNOWN_ERROR","NUMEQUAL must be in numeric range"], +["'abcdef' NOT","0 EQUAL","P2SH,STRICTENC","UNKNOWN_ERROR","NOT is an arithmetic operand"], +["2 DUP MUL","4 EQUAL","P2SH,STRICTENC","DISABLED_OPCODE","disabled"], +["2 DUP DIV","1 EQUAL","P2SH,STRICTENC","DISABLED_OPCODE","disabled"], +["2 2MUL","4 EQUAL","P2SH,STRICTENC","DISABLED_OPCODE","disabled"], +["2 2DIV","1 EQUAL","P2SH,STRICTENC","DISABLED_OPCODE","disabled"], +["7 3 MOD","1 EQUAL","P2SH,STRICTENC","DISABLED_OPCODE","disabled"], +["2 2 LSHIFT","8 EQUAL","P2SH,STRICTENC","DISABLED_OPCODE","disabled"], +["2 1 RSHIFT","1 EQUAL","P2SH,STRICTENC","DISABLED_OPCODE","disabled"], +["1","NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL","P2SH,STRICTENC","EVAL_FALSE"], +["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL","P2SH,STRICTENC","EVAL_FALSE"], +["1","NOP1","P2SH,DISCOURAGE_UPGRADABLE_NOPS","DISCOURAGE_UPGRADABLE_NOPS"], +["1","NOP4","P2SH,DISCOURAGE_UPGRADABLE_NOPS","DISCOURAGE_UPGRADABLE_NOPS"], +["1","NOP5","P2SH,DISCOURAGE_UPGRADABLE_NOPS","DISCOURAGE_UPGRADABLE_NOPS"], +["1","NOP6","P2SH,DISCOURAGE_UPGRADABLE_NOPS","DISCOURAGE_UPGRADABLE_NOPS"], +["1","NOP7","P2SH,DISCOURAGE_UPGRADABLE_NOPS","DISCOURAGE_UPGRADABLE_NOPS"], +["1","NOP8","P2SH,DISCOURAGE_UPGRADABLE_NOPS","DISCOURAGE_UPGRADABLE_NOPS"], +["1","NOP9","P2SH,DISCOURAGE_UPGRADABLE_NOPS","DISCOURAGE_UPGRADABLE_NOPS"], +["1","NOP10","P2SH,DISCOURAGE_UPGRADABLE_NOPS","DISCOURAGE_UPGRADABLE_NOPS"], +["NOP10","1","P2SH,DISCOURAGE_UPGRADABLE_NOPS","DISCOURAGE_UPGRADABLE_NOPS","Discouraged NOP10 in scriptSig"], +["1 0x01 0xb9","HASH160 0x14 0x15727299b05b45fdaf9ac9ecf7565cfe27c3e567 EQUAL","P2SH,DISCOURAGE_UPGRADABLE_NOPS","DISCOURAGE_UPGRADABLE_NOPS","Discouraged NOP10 in redeemScript"], +["0x50","1","P2SH,STRICTENC","BAD_OPCODE","opcode 0x50 is reserved"], +["1","IF 0xba ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE","opcodes above MAX_OPCODE invalid if executed"], +["1","IF 0xbb ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xbc ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xbd ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xbe ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xbf ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xc0 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xc1 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xc2 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xc3 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xc4 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xc5 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xc6 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xc7 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xc8 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xc9 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xca ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xcb ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xcc ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xcd ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xce ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xcf ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xd0 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xd1 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xd2 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xd3 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xd4 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xd5 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xd6 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xd7 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xd8 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xd9 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xda ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xdb ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xdc ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xdd ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xde ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xdf ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xe0 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xe1 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xe2 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xe3 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xe4 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xe5 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xe6 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xe7 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xe8 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xe9 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xea ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xeb ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xec ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xed ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xee ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xef ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xf0 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xf1 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xf2 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xf3 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xf4 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xf5 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xf6 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xf7 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xf8 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xf9 ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xfa ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xfb ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xfc ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xfd ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xfe ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1","IF 0xff ELSE 1 ENDIF","P2SH,STRICTENC","BAD_OPCODE"], +["1 IF 1 ELSE","0xff ENDIF","P2SH,STRICTENC","UNBALANCED_CONDITIONAL","invalid because scriptSig and scriptPubKey are processed separately"], +["NOP","RIPEMD160","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","SHA1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","SHA256","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","HASH160","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","HASH256","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'","P2SH,STRICTENC","PUSH_SIZE",">520 byte push"], +["0","IF 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' ENDIF 1","P2SH,STRICTENC","PUSH_SIZE",">520 byte push in non-executed IF branch"], +["1","0x61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161","P2SH,STRICTENC","OP_COUNT",">201 opcodes executed. 0x61 is NOP"], +["0","IF 0x6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161 ENDIF 1","P2SH,STRICTENC","OP_COUNT",">201 opcodes including non-executed IF branch. 0x61 is NOP"], +["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f","1 2 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f","P2SH,STRICTENC","STACK_SIZE",">1,000 stack size (0x6f is 3DUP)"], +["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f","1 TOALTSTACK 2 TOALTSTACK 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f","P2SH,STRICTENC","STACK_SIZE",">1,000 stack+altstack size"], +["NOP","0 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f 2DUP 0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161","P2SH,STRICTENC","SCRIPT_SIZE","10,001-byte scriptPubKey"], +["NOP1","NOP10","P2SH,STRICTENC","EVAL_FALSE"], +["1","VER","P2SH,STRICTENC","BAD_OPCODE","OP_VER is reserved"], +["1","VERIF","P2SH,STRICTENC","BAD_OPCODE","OP_VERIF is reserved"], +["1","VERNOTIF","P2SH,STRICTENC","BAD_OPCODE","OP_VERNOTIF is reserved"], +["1","RESERVED","P2SH,STRICTENC","BAD_OPCODE","OP_RESERVED is reserved"], +["1","RESERVED1","P2SH,STRICTENC","BAD_OPCODE","OP_RESERVED1 is reserved"], +["1","RESERVED2","P2SH,STRICTENC","BAD_OPCODE","OP_RESERVED2 is reserved"], +["1","0xba","P2SH,STRICTENC","BAD_OPCODE","0xba == MAX_OPCODE + 1"], +["2147483648","1ADD 1","P2SH,STRICTENC","UNKNOWN_ERROR","We cannot do math on 5-byte integers"], +["2147483648","NEGATE 1","P2SH,STRICTENC","UNKNOWN_ERROR","We cannot do math on 5-byte integers"], +["-2147483648","1ADD 1","P2SH,STRICTENC","UNKNOWN_ERROR","Because we use a sign bit, -2147483648 is also 5 bytes"], +["2147483647","1ADD 1SUB 1","P2SH,STRICTENC","UNKNOWN_ERROR","We cannot do math on 5-byte integers, even if the result is 4-bytes"], +["2147483648","1SUB 1","P2SH,STRICTENC","UNKNOWN_ERROR","We cannot do math on 5-byte integers, even if the result is 4-bytes"], +["2147483648 1","BOOLOR 1","P2SH,STRICTENC","UNKNOWN_ERROR","We cannot do BOOLOR on 5-byte integers (but we can still do IF etc)"], +["2147483648 1","BOOLAND 1","P2SH,STRICTENC","UNKNOWN_ERROR","We cannot do BOOLAND on 5-byte integers"], +["1","1 ENDIF","P2SH,STRICTENC","UNBALANCED_CONDITIONAL","ENDIF without IF"], +["1","IF 1","P2SH,STRICTENC","UNBALANCED_CONDITIONAL","IF without ENDIF"], +["1 IF 1","ENDIF","P2SH,STRICTENC","UNBALANCED_CONDITIONAL","IFs don't carry over"], +["NOP","IF 1 ENDIF","P2SH,STRICTENC","UNBALANCED_CONDITIONAL","The following tests check the if(stack.size() < N) tests in each opcode"], +["NOP","NOTIF 1 ENDIF","P2SH,STRICTENC","UNBALANCED_CONDITIONAL","They are here to catch copy-and-paste errors"], +["NOP","VERIFY 1","P2SH,STRICTENC","INVALID_STACK_OPERATION","Most of them are duplicated elsewhere,"], +["NOP","TOALTSTACK 1","P2SH,STRICTENC","INVALID_STACK_OPERATION","but, hey, more is always better, right?"], +["1","FROMALTSTACK","P2SH,STRICTENC","INVALID_ALTSTACK_OPERATION"], +["1","2DROP 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","2DUP","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1 1","3DUP","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1 1 1","2OVER","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1 1 1 1 1","2ROT","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1 1 1","2SWAP","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","IFDUP 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","DROP 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","DUP 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","NIP","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","OVER","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1 1 1 3","PICK","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["0","PICK 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1 1 1 3","ROLL","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["0","ROLL 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1 1","ROT","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","SWAP","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","TUCK","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","SIZE 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","EQUAL 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","EQUALVERIFY 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","1ADD 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","1SUB 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","NEGATE 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","ABS 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","NOT 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","0NOTEQUAL 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","ADD","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","SUB","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","BOOLAND","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","BOOLOR","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","NUMEQUAL","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","NUMEQUALVERIFY 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","NUMNOTEQUAL","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","LESSTHAN","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","GREATERTHAN","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","LESSTHANOREQUAL","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","GREATERTHANOREQUAL","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","MIN","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1","MAX","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["1 1","WITHIN","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","RIPEMD160 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","SHA1 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","SHA256 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","HASH160 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["NOP","HASH256 1","P2SH,STRICTENC","INVALID_STACK_OPERATION"], +["","CHECKSIG NOT","STRICTENC","INVALID_STACK_OPERATION","CHECKSIG must error when there are no stack items"], +["0","CHECKSIG NOT","STRICTENC","INVALID_STACK_OPERATION","CHECKSIG must error when there are not 2 stack items"], +["","CHECKMULTISIG NOT","STRICTENC","INVALID_STACK_OPERATION","CHECKMULTISIG must error when there are no stack items"], +["","-1 CHECKMULTISIG NOT","STRICTENC","PUBKEY_COUNT","CHECKMULTISIG must error when the specified number of pubkeys is negative"], +["","1 CHECKMULTISIG NOT","STRICTENC","INVALID_STACK_OPERATION","CHECKMULTISIG must error when there are not enough pubkeys on the stack"], +["","-1 0 CHECKMULTISIG NOT","STRICTENC","SIG_COUNT","CHECKMULTISIG must error when the specified number of signatures is negative"], +["","1 'pk1' 1 CHECKMULTISIG NOT","STRICTENC","INVALID_STACK_OPERATION","CHECKMULTISIG must error when there are not enough signatures on the stack"], +["","0 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG","P2SH,STRICTENC","OP_COUNT","202 CHECKMULTISIGS, fails due to 201 op limit"], +["1","0 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY","P2SH,STRICTENC","INVALID_STACK_OPERATION",""], +["","NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG","P2SH,STRICTENC","OP_COUNT","Fails due to 201 script operation limit"], +["1","NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY","P2SH,STRICTENC","OP_COUNT",""], +["0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21","21 CHECKMULTISIG 1","P2SH,STRICTENC","PUBKEY_COUNT","nPubKeys > 20"], +["0 'sig' 1 0","CHECKMULTISIG 1","P2SH,STRICTENC","SIG_COUNT","nSigs > nPubKeys"], +["NOP 0x01 1","HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL","P2SH,STRICTENC","SIG_PUSHONLY","Tests for Script.IsPushOnly()"], +["NOP1 0x01 1","HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL","P2SH,STRICTENC","SIG_PUSHONLY"], +["0 0x01 0x50","HASH160 0x14 0xece424a6bb6ddf4db592c0faed60685047a361b1 EQUAL","P2SH,STRICTENC","BAD_OPCODE","OP_RESERVED in P2SH should fail"], +["0 0x01 VER","HASH160 0x14 0x0f4d7845db968f2a81b530b6f3c1d6246d4c7e01 EQUAL","P2SH,STRICTENC","BAD_OPCODE","OP_VER in P2SH should fail"], +["0x00","'00' EQUAL","P2SH,STRICTENC","EVAL_FALSE","Basic OP_0 execution"], +["0x4c 0x00","DROP 1","MINIMALDATA","MINIMALDATA","Empty vector minimally represented by OP_0"], +["0x01 0x81","DROP 1","MINIMALDATA","MINIMALDATA","-1 minimally represented by OP_1NEGATE"], +["0x01 0x01","DROP 1","MINIMALDATA","MINIMALDATA","1 to 16 minimally represented by OP_1 to OP_16"], +["0x01 0x02","DROP 1","MINIMALDATA","MINIMALDATA"], +["0x01 0x03","DROP 1","MINIMALDATA","MINIMALDATA"], +["0x01 0x04","DROP 1","MINIMALDATA","MINIMALDATA"], +["0x01 0x05","DROP 1","MINIMALDATA","MINIMALDATA"], +["0x01 0x06","DROP 1","MINIMALDATA","MINIMALDATA"], +["0x01 0x07","DROP 1","MINIMALDATA","MINIMALDATA"], +["0x01 0x08","DROP 1","MINIMALDATA","MINIMALDATA"], +["0x01 0x09","DROP 1","MINIMALDATA","MINIMALDATA"], +["0x01 0x0a","DROP 1","MINIMALDATA","MINIMALDATA"], +["0x01 0x0b","DROP 1","MINIMALDATA","MINIMALDATA"], +["0x01 0x0c","DROP 1","MINIMALDATA","MINIMALDATA"], +["0x01 0x0d","DROP 1","MINIMALDATA","MINIMALDATA"], +["0x01 0x0e","DROP 1","MINIMALDATA","MINIMALDATA"], +["0x01 0x0f","DROP 1","MINIMALDATA","MINIMALDATA"], +["0x01 0x10","DROP 1","MINIMALDATA","MINIMALDATA"], +["0x4c 0x48 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111","DROP 1","MINIMALDATA","MINIMALDATA","PUSHDATA1 of 72 bytes minimally represented by direct push"], +["0x4d 0xFF00 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111","DROP 1","MINIMALDATA","MINIMALDATA","PUSHDATA2 of 255 bytes minimally represented by PUSHDATA1"], +["0x4e 0x00010000 0x11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111","DROP 1","MINIMALDATA","MINIMALDATA","PUSHDATA4 of 256 bytes minimally represented by PUSHDATA2"], +["0x01 0x00","NOT DROP 1","MINIMALDATA","UNKNOWN_ERROR","numequals 0"], +["0x02 0x0000","NOT DROP 1","MINIMALDATA","UNKNOWN_ERROR","numequals 0"], +["0x01 0x80","NOT DROP 1","MINIMALDATA","UNKNOWN_ERROR","0x80 (negative zero) numequals 0"], +["0x02 0x0080","NOT DROP 1","MINIMALDATA","UNKNOWN_ERROR","numequals 0"], +["0x02 0x0500","NOT DROP 1","MINIMALDATA","UNKNOWN_ERROR","numequals 5"], +["0x03 0x050000","NOT DROP 1","MINIMALDATA","UNKNOWN_ERROR","numequals 5"], +["0x02 0x0580","NOT DROP 1","MINIMALDATA","UNKNOWN_ERROR","numequals -5"], +["0x03 0x050080","NOT DROP 1","MINIMALDATA","UNKNOWN_ERROR","numequals -5"], +["0x03 0xff7f80","NOT DROP 1","MINIMALDATA","UNKNOWN_ERROR","Minimal encoding is 0xffff"], +["0x03 0xff7f00","NOT DROP 1","MINIMALDATA","UNKNOWN_ERROR","Minimal encoding is 0xff7f"], +["0x04 0xffff7f80","NOT DROP 1","MINIMALDATA","UNKNOWN_ERROR","Minimal encoding is 0xffffff"], +["0x04 0xffff7f00","NOT DROP 1","MINIMALDATA","UNKNOWN_ERROR","Minimal encoding is 0xffff7f"], +["1 0x02 0x0000","PICK DROP","MINIMALDATA","UNKNOWN_ERROR"], +["1 0x02 0x0000","ROLL DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0x02 0x0000","1ADD DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0x02 0x0000","1SUB DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0x02 0x0000","NEGATE DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0x02 0x0000","ABS DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0x02 0x0000","NOT DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0x02 0x0000","0NOTEQUAL DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0 0x02 0x0000","ADD DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0x02 0x0000 0","ADD DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0 0x02 0x0000","SUB DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0x02 0x0000 0","SUB DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0 0x02 0x0000","BOOLAND DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0x02 0x0000 0","BOOLAND DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0 0x02 0x0000","BOOLOR DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0x02 0x0000 0","BOOLOR DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0 0x02 0x0000","NUMEQUAL DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0x02 0x0000 1","NUMEQUAL DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0 0x02 0x0000","NUMEQUALVERIFY 1","MINIMALDATA","UNKNOWN_ERROR"], +["0x02 0x0000 0","NUMEQUALVERIFY 1","MINIMALDATA","UNKNOWN_ERROR"], +["0 0x02 0x0000","NUMNOTEQUAL DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0x02 0x0000 0","NUMNOTEQUAL DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0 0x02 0x0000","LESSTHAN DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0x02 0x0000 0","LESSTHAN DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0 0x02 0x0000","GREATERTHAN DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0x02 0x0000 0","GREATERTHAN DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0 0x02 0x0000","LESSTHANOREQUAL DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0x02 0x0000 0","LESSTHANOREQUAL DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0 0x02 0x0000","GREATERTHANOREQUAL DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0x02 0x0000 0","GREATERTHANOREQUAL DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0 0x02 0x0000","MIN DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0x02 0x0000 0","MIN DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0 0x02 0x0000","MAX DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0x02 0x0000 0","MAX DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0x02 0x0000 0 0","WITHIN DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0 0x02 0x0000 0","WITHIN DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0 0 0x02 0x0000","WITHIN DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0 0 0x02 0x0000","CHECKMULTISIG DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0 0x02 0x0000 0","CHECKMULTISIG DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0 0x02 0x0000 0 1","CHECKMULTISIG DROP 1","MINIMALDATA","UNKNOWN_ERROR"], +["0 0 0x02 0x0000","CHECKMULTISIGVERIFY 1","MINIMALDATA","UNKNOWN_ERROR"], +["0 0x02 0x0000 0","CHECKMULTISIGVERIFY 1","MINIMALDATA","UNKNOWN_ERROR"], +["0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501","2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0 2 CHECKMULTISIG NOT","STRICTENC","PUBKEYTYPE","2-of-2 CHECKMULTISIG NOT with the first pubkey invalid, and both signatures validly encoded."], +["0 0x47 0x3044022044dc17b0887c161bb67ba9635bf758735bdde503e4b0a0987f587f14a4e1143d022009a215772d49a85dae40d8ca03955af26ad3978a0ff965faa12915e9586249a501 1","2 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 0x21 0x02865c40293a680cb9c020e7b1e106d8c1916d3cef99aa431a56d253e69256dac0 2 CHECKMULTISIG NOT","STRICTENC","SIG_DER","2-of-2 CHECKMULTISIG NOT with both pubkeys valid, but first signature invalid."], +["0 0x47 0x304402205451ce65ad844dbb978b8bdedf5082e33b43cae8279c30f2c74d9e9ee49a94f802203fe95a7ccf74da7a232ee523ef4a53cb4d14bdd16289680cdb97a63819b8f42f01 0x46 0x304402205451ce65ad844dbb978b8bdedf5082e33b43cae8279c30f2c74d9e9ee49a94f802203fe95a7ccf74da7a232ee523ef4a53cb4d14bdd16289680cdb97a63819b8f42f","2 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 0x21 0x02a673638cb9587cb68ea08dbef685c6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5 3 CHECKMULTISIG","P2SH,STRICTENC","SIG_DER","2-of-3 with one valid and one invalid signature due to parse error, nSigs > validSigs"], +["0x4a 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","0 CHECKSIG NOT","DERSIG","SIG_DER","Overly long signature is incorrectly encoded for DERSIG"], +["0x25 0x30220220000000000000000000000000000000000000000000000000000000000000000000","0 CHECKSIG NOT","DERSIG","SIG_DER","Missing S is incorrectly encoded for DERSIG"], +["0x27 0x3024021077777777777777777777777777777777020a7777777777777777777777777777777701","0 CHECKSIG NOT","DERSIG","SIG_DER","S with invalid S length is incorrectly encoded for DERSIG"], +["0x27 0x302403107777777777777777777777777777777702107777777777777777777777777777777701","0 CHECKSIG NOT","DERSIG","SIG_DER","Non-integer R is incorrectly encoded for DERSIG"], +["0x27 0x302402107777777777777777777777777777777703107777777777777777777777777777777701","0 CHECKSIG NOT","DERSIG","SIG_DER","Non-integer S is incorrectly encoded for DERSIG"], +["0x17 0x3014020002107777777777777777777777777777777701","0 CHECKSIG NOT","DERSIG","SIG_DER","Zero-length R is incorrectly encoded for DERSIG"], +["0x17 0x3014021077777777777777777777777777777777020001","0 CHECKSIG NOT","DERSIG","SIG_DER","Zero-length S is incorrectly encoded for DERSIG"], +["0x27 0x302402107777777777777777777777777777777702108777777777777777777777777777777701","0 CHECKSIG NOT","DERSIG","SIG_DER","Negative S is incorrectly encoded for DERSIG"], +[["00",0E-8],"","0 0x206e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d","P2SH,WITNESS","EVAL_FALSE","Invalid witness script"], +[["51",0E-8],"","0 0x206e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d","P2SH,WITNESS","WITNESS_PROGRAM_MISMATCH","Witness script hash mismatch"], +[["00",0E-8],"","0 0x206e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d","","OK","Invalid witness script without WITNESS"], +[["51",0E-8],"","0 0x206e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d","","OK","Witness script hash mismatch without WITNESS"], +[["51",0E-8],"","-1 0x021234","P2SH,WITNESS","WITNESS_UNEXPECTED","OP_1NEGATE does not introduce a witness program"], +[["51",0E-8],"00","1 0x021234","P2SH,WITNESS","WITNESS_MALLEATED","OP_1 does introduce a witness program"], +[["51",0E-8],"00","16 0x021234","P2SH,WITNESS","WITNESS_MALLEATED","OP_16 does introduce a witness program"], +[["51",0E-8],"","NOP 0x021234","P2SH,WITNESS","WITNESS_UNEXPECTED","NOP does not introduce a witness program"], +["0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001","0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG","","OK","P2PK"], +["0x47 0x304402200a5c6163f07b8c3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001","0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG","","EVAL_FALSE","P2PK, bad sig"], +["0x47 0x304402206e05a6fe23c59196ffe176c9ddc31e73a9885638f9d1328d47c0c703863b8876022076feb53811aa5b04e0e79f938eb19906cc5e67548bc555a8e8b8b0fc603d840c01 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508","DUP HASH160 0x14 0x1018853670f9f3b0582c5b9ee8ce93764ac32b93 EQUALVERIFY CHECKSIG","","OK","P2PKH"], +["0x47 0x3044022034bb0494b50b8ef130e2185bb220265b9284ef5b4b8a8da4d8415df489c83b5102206259a26d9cc0a125ac26af6153b17c02956855ebe1467412f066e402f5f05d1201 0x21 0x03363d90d446b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640","DUP HASH160 0x14 0xc0834c0c158f53be706d234c38fd52de7eece656 EQUALVERIFY CHECKSIG","","EQUALVERIFY","P2PKH, bad pubkey"], +["0x47 0x304402204710a85181663b32d25c70ec2bbd14adff5ddfff6cb50d09e155ef5f541fc86c0220056b0cc949be9386ecc5f6c2ac0493269031dbb185781db90171b54ac127790281","0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG","","OK","P2PK anyonecanpay"], +["0x47 0x304402204710a85181663b32d25c70ec2bbd14adff5ddfff6cb50d09e155ef5f541fc86c0220056b0cc949be9386ecc5f6c2ac0493269031dbb185781db90171b54ac127790201","0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG","","EVAL_FALSE","P2PK anyonecanpay marked with normal hashtype"], +["0x47 0x3044022003fef42ed6c7be8917441218f525a60e2431be978e28b7aca4d7a532cc413ae8022067a1f82c74e8d69291b90d148778405c6257bbcfc2353cc38a3e1f22bf44254601 0x23 0x210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac","HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL","P2SH","OK","P2SH(P2PK)"], +["0x47 0x3044022003fef42ed6c7be8917441218f525a60e2431be978e28b7aca4d7a532cc413ae8022067a1f82c74e8d69291b90d148778405c6257bbcfc2353cc38a3e1f22bf44254601 0x23 0x210279be667ef9dcbbac54a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac","HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL","P2SH","EVAL_FALSE","P2SH(P2PK), bad redeemscript"], +["0x47 0x30440220781ba4f59a7b207a10db87628bc2168df4d59b844b397d2dbc9a5835fb2f2b7602206ed8fbcc1072fe2dfc5bb25909269e5dc42ffcae7ec2bc81d59692210ff30c2b01 0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x19 0x76a91491b24bf9f5288532960ac687abb035127b1d28a588ac","HASH160 0x14 0x7f67f0521934a57d3039f77f9f32cf313f3ac74b EQUAL","P2SH","OK","P2SH(P2PKH)"], +["0x47 0x304402204e2eb034be7b089534ac9e798cf6a2c79f38bcb34d1b179efd6f2de0841735db022071461beb056b5a7be1819da6a3e3ce3662831ecc298419ca101eb6887b5dd6a401 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac","HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL","","OK","P2SH(P2PKH), bad sig but no VERIFY_P2SH"], +["0x47 0x304402204e2eb034be7b089534ac9e798cf6a2c79f38bcb34d1b179efd6f2de0841735db022071461beb056b5a7be1819da6a3e3ce3662831ecc298419ca101eb6887b5dd6a401 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac","HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL","P2SH","EQUALVERIFY","P2SH(P2PKH), bad sig"], +["0 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901","3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG","","OK","3-of-3"], +["0 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0","3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG","","EVAL_FALSE","3-of-3, 2 sigs"], +["0 0x47 0x304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf8001 0x47 0x30440220563e5b3b1fc11662a84bc5ea2a32cc3819703254060ba30d639a1aaf2d5068ad0220601c1f47ddc76d93284dd9ed68f7c9974c4a0ea7cbe8a247d6bc3878567a5fca01 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae","HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL","P2SH","OK","P2SH(2-of-3)"], +["0 0x47 0x304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf8001 0 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae","HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL","P2SH","EVAL_FALSE","P2SH(2-of-3), 1 sig"], +["0x47 0x304402200060558477337b9022e70534f1fea71a318caf836812465a2509931c5e7c4987022078ec32bd50ac9e03a349ba953dfd9fe1c8d2dd8bdb1d38ddca844d3d5c78c11801","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","","OK","P2PK with too much R padding but no DERSIG"], +["0x47 0x304402200060558477337b9022e70534f1fea71a318caf836812465a2509931c5e7c4987022078ec32bd50ac9e03a349ba953dfd9fe1c8d2dd8bdb1d38ddca844d3d5c78c11801","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","DERSIG","SIG_DER","P2PK with too much R padding"], +["0x48 0x304502202de8c03fc525285c9c535631019a5f2af7c6454fa9eb392a3756a4917c420edd02210046130bf2baf7cfc065067c8b9e33a066d9c15edcea9feb0ca2d233e3597925b401","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","","OK","P2PK with too much S padding but no DERSIG"], +["0x48 0x304502202de8c03fc525285c9c535631019a5f2af7c6454fa9eb392a3756a4917c420edd02210046130bf2baf7cfc065067c8b9e33a066d9c15edcea9feb0ca2d233e3597925b401","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","DERSIG","SIG_DER","P2PK with too much S padding"], +["0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","","OK","P2PK with too little R padding but no DERSIG"], +["0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","DERSIG","SIG_DER","P2PK with too little R padding"], +["0x47 0x30440220005ece1335e7f757a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601","0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT","","OK","P2PK NOT with bad sig with too much R padding but no DERSIG"], +["0x47 0x30440220005ece1335e7f757a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601","0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT","DERSIG","SIG_DER","P2PK NOT with bad sig with too much R padding"], +["0x47 0x30440220005ece1335e7f657a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601","0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT","","EVAL_FALSE","P2PK NOT with too much R padding but no DERSIG"], +["0x47 0x30440220005ece1335e7f657a1a1f476a7fb5bd90964e8a022489f890614a04acfb734c002206c12b8294a6513c7710e8c82d3c23d75cdbfe83200eb7efb495701958501a5d601","0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT","DERSIG","SIG_DER","P2PK NOT with too much R padding"], +["0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","","OK","BIP66 example 1, without DERSIG"], +["0x47 0x30440220d7a0417c3f6d1a15094d1cf2a3378ca0503eb8a57630953a9e2987e21ddd0a6502207a6266d686c99090920249991d3d42065b6d43eb70187b219c0db82e4f94d1a201","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","DERSIG","SIG_DER","BIP66 example 1, with DERSIG"], +["0x47 0x304402208e43c0b91f7c1e5bc58e41c8185f8a6086e111b0090187968a86f2822462d3c902200a58f4076b1133b18ff1dc83ee51676e44c60cc608d9534e0df5ace0424fc0be01","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT","","EVAL_FALSE","BIP66 example 2, without DERSIG"], +["0x47 0x304402208e43c0b91f7c1e5bc58e41c8185f8a6086e111b0090187968a86f2822462d3c902200a58f4076b1133b18ff1dc83ee51676e44c60cc608d9534e0df5ace0424fc0be01","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT","DERSIG","SIG_DER","BIP66 example 2, with DERSIG"], +["0","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","","EVAL_FALSE","BIP66 example 3, without DERSIG"], +["0","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","DERSIG","EVAL_FALSE","BIP66 example 3, with DERSIG"], +["0","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT","","OK","BIP66 example 4, without DERSIG"], +["0","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT","DERSIG","OK","BIP66 example 4, with DERSIG"], +["0x09 0x300602010102010101","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT","DERSIG","OK","BIP66 example 4, with DERSIG, non-null DER-compliant signature"], +["0","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT","DERSIG,NULLFAIL","OK","BIP66 example 4, with DERSIG and NULLFAIL"], +["0x09 0x300602010102010101","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT","DERSIG,NULLFAIL","NULLFAIL","BIP66 example 4, with DERSIG and NULLFAIL, non-null DER-compliant signature"], +["1","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","","EVAL_FALSE","BIP66 example 5, without DERSIG"], +["1","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG","DERSIG","SIG_DER","BIP66 example 5, with DERSIG"], +["1","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT","","OK","BIP66 example 6, without DERSIG"], +["1","0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG NOT","DERSIG","SIG_DER","BIP66 example 6, with DERSIG"], +["0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0x47 0x3044022027c2714269ca5aeecc4d70edc88ba5ee0e3da4986e9216028f489ab4f1b8efce022022bd545b4951215267e4c5ceabd4c5350331b2e4a0b6494c56f361fa5a57a1a201","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG","","OK","BIP66 example 7, without DERSIG"], +["0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0x47 0x3044022027c2714269ca5aeecc4d70edc88ba5ee0e3da4986e9216028f489ab4f1b8efce022022bd545b4951215267e4c5ceabd4c5350331b2e4a0b6494c56f361fa5a57a1a201","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG","DERSIG","SIG_DER","BIP66 example 7, with DERSIG"], +["0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0x47 0x3044022079ea80afd538d9ada421b5101febeb6bc874e01dde5bca108c1d0479aec339a4022004576db8f66130d1df686ccf00935703689d69cf539438da1edab208b0d63c4801","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT","","EVAL_FALSE","BIP66 example 8, without DERSIG"], +["0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0x47 0x3044022079ea80afd538d9ada421b5101febeb6bc874e01dde5bca108c1d0479aec339a4022004576db8f66130d1df686ccf00935703689d69cf539438da1edab208b0d63c4801","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT","DERSIG","SIG_DER","BIP66 example 8, with DERSIG"], +["0 0 0x47 0x3044022081aa9d436f2154e8b6d600516db03d78de71df685b585a9807ead4210bd883490220534bb6bdf318a419ac0749660b60e78d17d515558ef369bf872eff405b676b2e01","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG","","EVAL_FALSE","BIP66 example 9, without DERSIG"], +["0 0 0x47 0x3044022081aa9d436f2154e8b6d600516db03d78de71df685b585a9807ead4210bd883490220534bb6bdf318a419ac0749660b60e78d17d515558ef369bf872eff405b676b2e01","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG","DERSIG","SIG_DER","BIP66 example 9, with DERSIG"], +["0 0 0x47 0x30440220da6f441dc3b4b2c84cfa8db0cd5b34ed92c9e01686de5a800d40498b70c0dcac02207c2cf91b0c32b860c4cd4994be36cfb84caf8bb7c3a8e4d96a31b2022c5299c501","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT","","OK","BIP66 example 10, without DERSIG"], +["0 0 0x47 0x30440220da6f441dc3b4b2c84cfa8db0cd5b34ed92c9e01686de5a800d40498b70c0dcac02207c2cf91b0c32b860c4cd4994be36cfb84caf8bb7c3a8e4d96a31b2022c5299c501","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT","DERSIG","SIG_DER","BIP66 example 10, with DERSIG"], +["0 0x47 0x30440220cae00b1444babfbf6071b0ba8707f6bd373da3df494d6e74119b0430c5db810502205d5231b8c5939c8ff0c82242656d6e06edb073d42af336c99fe8837c36ea39d501 0","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG","","EVAL_FALSE","BIP66 example 11, without DERSIG"], +["0 0x47 0x30440220b119d67d389315308d1745f734a51ff3ec72e06081e84e236fdf9dc2f5d2a64802204b04e3bc38674c4422ea317231d642b56dc09d214a1ecbbf16ecca01ed996e2201 0","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 2 CHECKMULTISIG NOT","","OK","BIP66 example 12, without DERSIG"], +["0x48 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb12510101","0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG","DERSIG","SIG_DER","P2PK with multi-byte hashtype, with DERSIG"], +["0x48 0x304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef001","0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG","","OK","P2PK with high S but no LOW_S"], +["0x47 0x3044022057292e2d4dfe775becdd0a9e6547997c728cdf35390f6a017da56d654d374e4902206b643be2fc53763b4e284845bfea2c597d2dc7759941dce937636c9d341b71ed01","0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG","","OK","P2PK with hybrid pubkey but no STRICTENC"], +["0x47 0x30440220035d554e3153c14950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101","0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT","","EVAL_FALSE","P2PK NOT with hybrid pubkey but no STRICTENC"], +["0x47 0x30440220035d554e3153c04950c9993f41c496607a8e24093db0595be7bf875cf64fcf1f02204731c8c4e5daf15e706cec19cdd8f2c5b1d05490e11dab8465ed426569b6e92101","0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT","","OK","P2PK NOT with invalid hybrid pubkey but no STRICTENC"], +["0 0x47 0x304402202e79441ad1baf5a07fb86bae3753184f6717d9692680947ea8b6e8b777c69af1022079a262e13d868bb5a0964fefe3ba26942e1b0669af1afb55ef3344bc9d4fc4c401","1 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG","","OK","1-of-2 with the second 1 hybrid pubkey and no STRICTENC"], +["0 0x47 0x304402202e79441ad1baf5a07fb86bae3753184f6717d9692680947ea8b6e8b777c69af1022079a262e13d868bb5a0964fefe3ba26942e1b0669af1afb55ef3344bc9d4fc4c401","1 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG","STRICTENC","OK","1-of-2 with the second 1 hybrid pubkey"], +["0 0x47 0x3044022079c7824d6c868e0e1a273484e28c2654a27d043c8a27f49f52cb72efed0759090220452bbbf7089574fa082095a4fc1b3a16bafcf97a3a34d745fafc922cce66b27201","1 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 2 CHECKMULTISIG","STRICTENC","PUBKEYTYPE","1-of-2 with the first 1 hybrid pubkey"], +["0x47 0x304402206177d513ec2cda444c021a1f4f656fc4c72ba108ae063e157eb86dc3575784940220666fc66702815d0e5413bb9b1df22aed44f5f1efb8b99d41dd5dc9a5be6d205205","0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG","","OK","P2PK with undefined hashtype but no STRICTENC"], +["0x47 0x304402207409b5b320296e5e2136a7b281a7f803028ca4ca44e2b83eebd46932677725de02202d4eea1c8d3c98e6f42614f54764e6e5e6542e213eb4d079737e9a8b6e9812ec05","0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG NOT","","OK","P2PK NOT with invalid sig and undefined hashtype but no STRICTENC"], +["1 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901","3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG","","OK","3-of-3 with nonzero dummy but no NULLDUMMY"], +["1 0x47 0x3044022051254b9fb476a52d85530792b578f86fea70ec1ffb4393e661bcccb23d8d63d3022076505f94a403c86097841944e044c70c2045ce90e36de51f7e9d3828db98a07501 0x47 0x304402200a358f750934b3feb822f1966bfcd8bbec9eeaa3a8ca941e11ee5960e181fa01022050bf6b5a8e7750f70354ae041cb68a7bade67ec6c3ab19eb359638974410626e01 0x47 0x304402200955d031fff71d8653221e85e36c3c85533d2312fc3045314b19650b7ae2f81002202a6bb8505e36201909d0921f01abff390ae6b7ff97bbf959f98aedeb0a56730901","3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG","NULLDUMMY","SIG_NULLDUMMY","3-of-3 with nonzero dummy"], +["1 0x47 0x304402201bb2edab700a5d020236df174fefed78087697143731f659bea59642c759c16d022061f42cdbae5bcd3e8790f20bf76687443436e94a634321c16a72aa54cbc7c2ea01 0x47 0x304402204bb4a64f2a6e5c7fb2f07fef85ee56fde5e6da234c6a984262307a20e99842d702206f8303aaba5e625d223897e2ffd3f88ef1bcffef55f38dc3768e5f2e94c923f901 0x47 0x3044022040c2809b71fffb155ec8b82fe7a27f666bd97f941207be4e14ade85a1249dd4d02204d56c85ec525dd18e29a0533d5ddf61b6b1bb32980c2f63edf951aebf7a27bfe01","3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG NOT","","OK","3-of-3 NOT with invalid sig and nonzero dummy but no NULLDUMMY"], +["1 0x47 0x304402201bb2edab700a5d020236df174fefed78087697143731f659bea59642c759c16d022061f42cdbae5bcd3e8790f20bf76687443436e94a634321c16a72aa54cbc7c2ea01 0x47 0x304402204bb4a64f2a6e5c7fb2f07fef85ee56fde5e6da234c6a984262307a20e99842d702206f8303aaba5e625d223897e2ffd3f88ef1bcffef55f38dc3768e5f2e94c923f901 0x47 0x3044022040c2809b71fffb155ec8b82fe7a27f666bd97f941207be4e14ade85a1249dd4d02204d56c85ec525dd18e29a0533d5ddf61b6b1bb32980c2f63edf951aebf7a27bfe01","3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG NOT","NULLDUMMY","SIG_NULLDUMMY","3-of-3 NOT with invalid sig with nonzero dummy"], +["0 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901 DUP","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG","","OK","2-of-2 with two identical keys and sigs pushed using OP_DUP but no SIGPUSHONLY"], +["0 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901 DUP","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG","SIGPUSHONLY","SIG_PUSHONLY","2-of-2 with two identical keys and sigs pushed using OP_DUP"], +["0x47 0x3044022018a2a81a93add5cb5f5da76305718e4ea66045ec4888b28d84cb22fae7f4645b02201e6daa5ed5d2e4b2b2027cf7ffd43d8d9844dd49f74ef86899ec8e669dfd39aa01 NOP8 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac","HASH160 0x14 0x215640c2f72f0d16b4eced26762035a42ffed39a EQUAL","","OK","P2SH(P2PK) with non-push scriptSig but no P2SH or SIGPUSHONLY"], +["0x47 0x304402203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022054e1c258c2981cdfba5df1f46661fb6541c44f77ca0092f3600331abfffb125101 NOP8","0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG","","OK","P2PK with non-push scriptSig but with P2SH validation"], +["0x47 0x3044022018a2a81a93add5cb5f5da76305718e4ea66045ec4888b28d84cb22fae7f4645b02201e6daa5ed5d2e4b2b2027cf7ffd43d8d9844dd49f74ef86899ec8e669dfd39aa01 NOP8 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac","HASH160 0x14 0x215640c2f72f0d16b4eced26762035a42ffed39a EQUAL","P2SH","SIG_PUSHONLY","P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY"], +["0x47 0x3044022018a2a81a93add5cb5f5da76305718e4ea66045ec4888b28d84cb22fae7f4645b02201e6daa5ed5d2e4b2b2027cf7ffd43d8d9844dd49f74ef86899ec8e669dfd39aa01 NOP8 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac","HASH160 0x14 0x215640c2f72f0d16b4eced26762035a42ffed39a EQUAL","SIGPUSHONLY","SIG_PUSHONLY","P2SH(P2PK) with non-push scriptSig but not P2SH"], +["0 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901 0x47 0x304402200abeb4bd07f84222f474aed558cfbdfc0b4e96cde3c2935ba7098b1ff0bd74c302204a04c1ca67b2a20abee210cf9a21023edccbbf8024b988812634233115c6b73901","2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG","SIGPUSHONLY","OK","2-of-2 with two identical keys and sigs pushed"], +["11 0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001","0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG","P2SH","OK","P2PK with unnecessary input but no CLEANSTACK"], +["11 0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001","0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG","CLEANSTACK,P2SH","CLEANSTACK","P2PK with unnecessary input"], +["11 0x47 0x304402202f7505132be14872581f35d74b759212d9da40482653f1ffa3116c3294a4a51702206adbf347a2240ca41c66522b1a22a41693610b76a8e7770645dc721d1635854f01 0x43 0x410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac","HASH160 0x14 0x31edc23bdafda4639e669f89ad6b2318dd79d032 EQUAL","P2SH","OK","P2SH with unnecessary input but no CLEANSTACK"], +["11 0x47 0x304402202f7505132be14872581f35d74b759212d9da40482653f1ffa3116c3294a4a51702206adbf347a2240ca41c66522b1a22a41693610b76a8e7770645dc721d1635854f01 0x43 0x410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac","HASH160 0x14 0x31edc23bdafda4639e669f89ad6b2318dd79d032 EQUAL","CLEANSTACK,P2SH","CLEANSTACK","P2SH with unnecessary input"], +["0x47 0x304402202f7505132be14872581f35d74b759212d9da40482653f1ffa3116c3294a4a51702206adbf347a2240ca41c66522b1a22a41693610b76a8e7770645dc721d1635854f01 0x43 0x410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac","HASH160 0x14 0x31edc23bdafda4639e669f89ad6b2318dd79d032 EQUAL","CLEANSTACK,P2SH","OK","P2SH with CLEANSTACK"], +[["304402200d461c140cfdfcf36b94961db57ae8c18d1cb80e9d95a9e47ac22470c1bf125502201c8dc1cbfef6a3ef90acbbb992ca22fe9466ee6f9d4898eda277a7ac3ab4b25101","410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac",1E-8],"","0 0x20 0xb95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64","P2SH,WITNESS","OK","Basic P2WSH"], +[["304402201e7216e5ccb3b61d46946ec6cc7e8c4e0117d13ac2fd4b152197e4805191c74202203e9903e33e84d9ee1dd13fb057afb7ccfb47006c23f6a067185efbc9dd780fc501","0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",1E-8],"","0 0x14 0x91b24bf9f5288532960ac687abb035127b1d28a5","P2SH,WITNESS","OK","Basic P2WPKH"], +[["3044022066e02c19a513049d49349cf5311a1b012b7c4fae023795a18ab1d91c23496c22022025e216342c8e07ce8ef51e8daee88f84306a9de66236cab230bb63067ded1ad301","410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac",1E-8],"0x22 0x0020b95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64","HASH160 0x14 0xf386c2ba255cc56d20cfa6ea8b062f8b59945518 EQUAL","P2SH,WITNESS","OK","Basic P2SH(P2WSH)"], +[["304402200929d11561cd958460371200f82e9cae64c727a495715a31828e27a7ad57b36d0220361732ced04a6f97351ecca21a56d0b8cd4932c1da1f8f569a2b68e5e48aed7801","0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",1E-8],"0x16 0x001491b24bf9f5288532960ac687abb035127b1d28a5","HASH160 0x14 0x17743beb429c55c942d2ec703b98c4d57c2df5c6 EQUAL","P2SH,WITNESS","OK","Basic P2SH(P2WPKH)"], +[["304402202589f0512cb2408fb08ed9bd24f85eb3059744d9e4f2262d0b7f1338cff6e8b902206c0978f449693e0578c71bc543b11079fd0baae700ee5e9a6bee94db490af9fc01","41048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26cafac",0E-8],"","0 0x20 0xac8ebd9e52c17619a381fa4f71aebb696087c6ef17c960fd0587addad99c0610","P2SH,WITNESS","EVAL_FALSE","Basic P2WSH with the wrong key"], +[["304402206ef7fdb2986325d37c6eb1a8bb24aeb46dede112ed8fc76c7d7500b9b83c0d3d02201edc2322c794fe2d6b0bd73ed319e714aa9b86d8891961530d5c9b7156b60d4e01","048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf",0E-8],"","0 0x14 0x7cf9c846cd4882efec4bf07e44ebdad495c94f4b","P2SH,WITNESS","EVAL_FALSE","Basic P2WPKH with the wrong key"], +[["30440220069ea3581afaf8187f63feee1fd2bd1f9c0dc71ea7d6e8a8b07ee2ebcf824bf402201a4fdef4c532eae59223be1eda6a397fc835142d4ddc6c74f4aa85b766a5c16f01","41048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26cafac",0E-8],"0x22 0x0020ac8ebd9e52c17619a381fa4f71aebb696087c6ef17c960fd0587addad99c0610","HASH160 0x14 0x61039a003883787c0d6ebc66d97fdabe8e31449d EQUAL","P2SH,WITNESS","EVAL_FALSE","Basic P2SH(P2WSH) with the wrong key"], +[["304402204209e49457c2358f80d0256bc24535b8754c14d08840fc4be762d6f5a0aed80b02202eaf7d8fc8d62f60c67adcd99295528d0e491ae93c195cec5a67e7a09532a88001","048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf",0E-8],"0x16 0x00147cf9c846cd4882efec4bf07e44ebdad495c94f4b","HASH160 0x14 0x4e0c2aed91315303fc6a1dc4c7bc21c88f75402e EQUAL","P2SH,WITNESS","EVAL_FALSE","Basic P2SH(P2WPKH) with the wrong key"], +[["304402202589f0512cb2408fb08ed9bd24f85eb3059744d9e4f2262d0b7f1338cff6e8b902206c0978f449693e0578c71bc543b11079fd0baae700ee5e9a6bee94db490af9fc01","41048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26cafac",0E-8],"","0 0x20 0xac8ebd9e52c17619a381fa4f71aebb696087c6ef17c960fd0587addad99c0610","P2SH","OK","Basic P2WSH with the wrong key but no WITNESS"], +[["304402206ef7fdb2986325d37c6eb1a8bb24aeb46dede112ed8fc76c7d7500b9b83c0d3d02201edc2322c794fe2d6b0bd73ed319e714aa9b86d8891961530d5c9b7156b60d4e01","048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf",0E-8],"","0 0x14 0x7cf9c846cd4882efec4bf07e44ebdad495c94f4b","P2SH","OK","Basic P2WPKH with the wrong key but no WITNESS"], +[["30440220069ea3581afaf8187f63feee1fd2bd1f9c0dc71ea7d6e8a8b07ee2ebcf824bf402201a4fdef4c532eae59223be1eda6a397fc835142d4ddc6c74f4aa85b766a5c16f01","41048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26cafac",0E-8],"0x22 0x0020ac8ebd9e52c17619a381fa4f71aebb696087c6ef17c960fd0587addad99c0610","HASH160 0x14 0x61039a003883787c0d6ebc66d97fdabe8e31449d EQUAL","P2SH","OK","Basic P2SH(P2WSH) with the wrong key but no WITNESS"], +[["304402204209e49457c2358f80d0256bc24535b8754c14d08840fc4be762d6f5a0aed80b02202eaf7d8fc8d62f60c67adcd99295528d0e491ae93c195cec5a67e7a09532a88001","048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf",0E-8],"0x16 0x00147cf9c846cd4882efec4bf07e44ebdad495c94f4b","HASH160 0x14 0x4e0c2aed91315303fc6a1dc4c7bc21c88f75402e EQUAL","P2SH","OK","Basic P2SH(P2WPKH) with the wrong key but no WITNESS"], +[["3044022066faa86e74e8b30e82691b985b373de4f9e26dc144ec399c4f066aa59308e7c202204712b86f28c32503faa051dbeabff2c238ece861abc36c5e0b40b1139ca222f001","410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac",0E-8],"","0 0x20 0xb95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64","P2SH,WITNESS","EVAL_FALSE","Basic P2WSH with wrong value"], +[["304402203b3389b87448d7dfdb5e82fb854fcf92d7925f9938ea5444e36abef02c3d6a9602202410bc3265049abb07fd2e252c65ab7034d95c9d5acccabe9fadbdc63a52712601","0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",0E-8],"","0 0x14 0x91b24bf9f5288532960ac687abb035127b1d28a5","P2SH,WITNESS","EVAL_FALSE","Basic P2WPKH with wrong value"], +[["3044022000a30c4cfc10e4387be528613575434826ad3c15587475e0df8ce3b1746aa210022008149265e4f8e9dafe1f3ea50d90cb425e9e40ea7ebdd383069a7cfa2b77004701","410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac",0E-8],"0x22 0x0020b95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64","HASH160 0x14 0xf386c2ba255cc56d20cfa6ea8b062f8b59945518 EQUAL","P2SH,WITNESS","EVAL_FALSE","Basic P2SH(P2WSH) with wrong value"], +[["304402204fc3a2cd61a47913f2a5f9107d0ad4a504c7b31ee2d6b3b2f38c2b10ee031e940220055d58b7c3c281aaa381d8f486ac0f3e361939acfd568046cb6a311cdfa974cf01","0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",0E-8],"0x16 0x001491b24bf9f5288532960ac687abb035127b1d28a5","HASH160 0x14 0x17743beb429c55c942d2ec703b98c4d57c2df5c6 EQUAL","P2SH,WITNESS","EVAL_FALSE","Basic P2SH(P2WPKH) with wrong value"], +[["3044022039105b995a5f448639a997a5c90fda06f50b49df30c3bdb6663217bf79323db002206fecd54269dec569fcc517178880eb58bb40f381a282bb75766ff3637d5f4b4301","400479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac",0E-8],"","0 0x20 0xb95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64","P2SH,WITNESS","WITNESS_PROGRAM_MISMATCH","P2WSH with witness program mismatch"], +[["304402201a96950593cb0af32d080b0f193517f4559241a8ebd1e95e414533ad64a3f423022047f4f6d3095c23235bdff3aeff480d0529c027a3f093cb265b7cbf148553b85101","0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8","",0E-8],"","0 0x14 0x91b24bf9f5288532960ac687abb035127b1d28a5","P2SH,WITNESS","WITNESS_PROGRAM_MISMATCH","P2WPKH with witness program mismatch"], +[["304402201a96950593cb0af32d080b0f193517f4559241a8ebd1e95e414533ad64a3f423022047f4f6d3095c23235bdff3aeff480d0529c027a3f093cb265b7cbf148553b85101","0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",0E-8],"11","0 0x14 0x91b24bf9f5288532960ac687abb035127b1d28a5","P2SH,WITNESS","WITNESS_MALLEATED","P2WPKH with non-empty scriptSig"], +[["",0E-8],"0x47 0x304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001","0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG","P2SH,WITNESS","WITNESS_UNEXPECTED","P2PK with witness"], +[["304402204256146fcf8e73b0fd817ffa2a4e408ff0418ff987dd08a4f485b62546f6c43c02203f3c8c3e2febc051e1222867f5f9d0eaf039d6792911c10940aa3cc74123378e01","210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac",1E-8],"","0 0x20 0x1863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262","P2SH,WITNESS,WITNESS_PUBKEYTYPE","OK","Basic P2WSH with compressed key"], +[["304402204edf27486f11432466b744df533e1acac727e0c83e5f912eb289a3df5bf8035f022075809fdd876ede40ad21667eba8b7e96394938f9c9c50f11b6a1280cce2cea8601","0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",1E-8],"","0 0x14 0x751e76e8199196d454941c45d1b3a323f1433bd6","P2SH,WITNESS,WITNESS_PUBKEYTYPE","OK","Basic P2WPKH with compressed key"], +[["304402203a549090cc46bce1e5e95c4922ea2c12747988e0207b04c42f81cdbe87bb1539022050f57a245b875fd5119c419aaf050bcdf41384f0765f04b809e5bced1fe7093d01","210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac",1E-8],"0x22 0x00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262","HASH160 0x14 0xe4300531190587e3880d4c3004f5355d88ff928d EQUAL","P2SH,WITNESS,WITNESS_PUBKEYTYPE","OK","Basic P2SH(P2WSH) with compressed key"], +[["304402201bc0d53046827f4a35a3166e33e3b3366c4085540dc383b95d21ed2ab11e368a0220333e78c6231214f5f8e59621e15d7eeab0d4e4d0796437e00bfbd2680c5f9c1701","0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",1E-8],"0x16 0x0014751e76e8199196d454941c45d1b3a323f1433bd6","HASH160 0x14 0xbcfeb728b584253d5f3f70bcb780e9ef218a68f4 EQUAL","P2SH,WITNESS,WITNESS_PUBKEYTYPE","OK","Basic P2SH(P2WPKH) with compressed key"], +["","CHECKSEQUENCEVERIFY","CHECKSEQUENCEVERIFY","INVALID_STACK_OPERATION","CSV automatically fails on an empty stack"], +["-1","CHECKSEQUENCEVERIFY","CHECKSEQUENCEVERIFY","NEGATIVE_LOCKTIME","CSV automatically fails if stack top is negative"], +["0x0100","CHECKSEQUENCEVERIFY","CHECKSEQUENCEVERIFY,MINIMALDATA","UNKNOWN_ERROR","CSV fails if stack top is not minimally encoded"], +["1","IF 1 ENDIF","P2SH,WITNESS,MINIMALIF","OK"], +["2","IF 1 ENDIF","P2SH,WITNESS,MINIMALIF","OK"], +["0x02 0x0100","IF 1 ENDIF","P2SH,WITNESS,MINIMALIF","OK"], +["0","IF 1 ENDIF","P2SH,WITNESS,MINIMALIF","EVAL_FALSE"], +["0x01 0x00","IF 1 ENDIF","P2SH,WITNESS,MINIMALIF","EVAL_FALSE"], +["1","NOTIF 1 ENDIF","P2SH,WITNESS,MINIMALIF","EVAL_FALSE"], +["2","NOTIF 1 ENDIF","P2SH,WITNESS,MINIMALIF","EVAL_FALSE"], +["0x02 0x0100","NOTIF 1 ENDIF","P2SH,WITNESS,MINIMALIF","EVAL_FALSE"], +["0","NOTIF 1 ENDIF","P2SH,WITNESS,MINIMALIF","OK"], +["0x01 0x00","NOTIF 1 ENDIF","P2SH,WITNESS,MINIMALIF","OK"], +["1 0x03 0x635168","HASH160 0x14 0xe7309652a8e3f600f06f5d8d52d6df03d2176cc3 EQUAL","P2SH,WITNESS,MINIMALIF","OK"], +["2 0x03 0x635168","HASH160 0x14 0xe7309652a8e3f600f06f5d8d52d6df03d2176cc3 EQUAL","P2SH,WITNESS,MINIMALIF","OK"], +["0x02 0x0100 0x03 0x635168","HASH160 0x14 0xe7309652a8e3f600f06f5d8d52d6df03d2176cc3 EQUAL","P2SH,WITNESS,MINIMALIF","OK"], +["0 0x03 0x635168","HASH160 0x14 0xe7309652a8e3f600f06f5d8d52d6df03d2176cc3 EQUAL","P2SH,WITNESS,MINIMALIF","EVAL_FALSE"], +["0x01 0x00 0x03 0x635168","HASH160 0x14 0xe7309652a8e3f600f06f5d8d52d6df03d2176cc3 EQUAL","P2SH,WITNESS,MINIMALIF","EVAL_FALSE"], +["0x03 0x635168","HASH160 0x14 0xe7309652a8e3f600f06f5d8d52d6df03d2176cc3 EQUAL","P2SH,WITNESS,MINIMALIF","UNBALANCED_CONDITIONAL"], +["1 0x03 0x645168","HASH160 0x14 0x0c3f8fe3d6ca266e76311ecda544c67d15fdd5b0 EQUAL","P2SH,WITNESS,MINIMALIF","EVAL_FALSE"], +["2 0x03 0x645168","HASH160 0x14 0x0c3f8fe3d6ca266e76311ecda544c67d15fdd5b0 EQUAL","P2SH,WITNESS,MINIMALIF","EVAL_FALSE"], +["0x02 0x0100 0x03 0x645168","HASH160 0x14 0x0c3f8fe3d6ca266e76311ecda544c67d15fdd5b0 EQUAL","P2SH,WITNESS,MINIMALIF","EVAL_FALSE"], +["0 0x03 0x645168","HASH160 0x14 0x0c3f8fe3d6ca266e76311ecda544c67d15fdd5b0 EQUAL","P2SH,WITNESS,MINIMALIF","OK"], +["0x01 0x00 0x03 0x645168","HASH160 0x14 0x0c3f8fe3d6ca266e76311ecda544c67d15fdd5b0 EQUAL","P2SH,WITNESS,MINIMALIF","OK"], +["0x03 0x645168","HASH160 0x14 0x0c3f8fe3d6ca266e76311ecda544c67d15fdd5b0 EQUAL","P2SH,WITNESS,MINIMALIF","UNBALANCED_CONDITIONAL"], +[["01","635168",1E-8],"","0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","P2SH,WITNESS","OK"], +[["02","635168",1E-8],"","0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","P2SH,WITNESS","OK"], +[["0100","635168",1E-8],"","0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","P2SH,WITNESS","OK"], +[["","635168",1E-8],"","0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","P2SH,WITNESS","CLEANSTACK"], +[["00","635168",1E-8],"","0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","P2SH,WITNESS","CLEANSTACK"], +[["01","635168",1E-8],"","0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","P2SH,WITNESS,MINIMALIF","OK"], +[["02","635168",1E-8],"","0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","P2SH,WITNESS,MINIMALIF","MINIMALIF"], +[["0100","635168",1E-8],"","0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","P2SH,WITNESS,MINIMALIF","MINIMALIF"], +[["","635168",1E-8],"","0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","P2SH,WITNESS,MINIMALIF","CLEANSTACK"], +[["00","635168",1E-8],"","0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","P2SH,WITNESS,MINIMALIF","MINIMALIF"], +[["635168",1E-8],"","0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","P2SH,WITNESS","UNBALANCED_CONDITIONAL"], +[["635168",1E-8],"","0 0x20 0xc7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","P2SH,WITNESS,MINIMALIF","UNBALANCED_CONDITIONAL"], +[["01","645168",1E-8],"","0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","P2SH,WITNESS","CLEANSTACK"], +[["02","645168",1E-8],"","0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","P2SH,WITNESS","CLEANSTACK"], +[["0100","645168",1E-8],"","0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","P2SH,WITNESS","CLEANSTACK"], +[["","645168",1E-8],"","0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","P2SH,WITNESS","OK"], +[["00","645168",1E-8],"","0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","P2SH,WITNESS","OK"], +[["01","645168",1E-8],"","0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","P2SH,WITNESS,MINIMALIF","CLEANSTACK"], +[["02","645168",1E-8],"","0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","P2SH,WITNESS,MINIMALIF","MINIMALIF"], +[["0100","645168",1E-8],"","0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","P2SH,WITNESS,MINIMALIF","MINIMALIF"], +[["","645168",1E-8],"","0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","P2SH,WITNESS,MINIMALIF","OK"], +[["00","645168",1E-8],"","0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","P2SH,WITNESS,MINIMALIF","MINIMALIF"], +[["645168",1E-8],"","0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","P2SH,WITNESS","UNBALANCED_CONDITIONAL"], +[["645168",1E-8],"","0 0x20 0xf913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","P2SH,WITNESS,MINIMALIF","UNBALANCED_CONDITIONAL"], +[["01","635168",1E-8],"0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL","P2SH,WITNESS","OK"], +[["02","635168",1E-8],"0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL","P2SH,WITNESS","OK"], +[["0100","635168",1E-8],"0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL","P2SH,WITNESS","OK"], +[["","635168",1E-8],"0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL","P2SH,WITNESS","CLEANSTACK"], +[["00","635168",1E-8],"0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL","P2SH,WITNESS","CLEANSTACK"], +[["01","635168",1E-8],"0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL","P2SH,WITNESS,MINIMALIF","OK"], +[["02","635168",1E-8],"0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL","P2SH,WITNESS,MINIMALIF","MINIMALIF"], +[["0100","635168",1E-8],"0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL","P2SH,WITNESS,MINIMALIF","MINIMALIF"], +[["","635168",1E-8],"0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL","P2SH,WITNESS,MINIMALIF","CLEANSTACK"], +[["00","635168",1E-8],"0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL","P2SH,WITNESS,MINIMALIF","MINIMALIF"], +[["635168",1E-8],"0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL","P2SH,WITNESS","UNBALANCED_CONDITIONAL"], +[["635168",1E-8],"0x22 0x0020c7eaf06d5ae01a58e376e126eb1e6fab2036076922b96b2711ffbec1e590665d","HASH160 0x14 0x9b27ee6d9010c21bf837b334d043be5d150e7ba7 EQUAL","P2SH,WITNESS,MINIMALIF","UNBALANCED_CONDITIONAL"], +[["01","645168",1E-8],"0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL","P2SH,WITNESS","CLEANSTACK"], +[["02","645168",1E-8],"0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL","P2SH,WITNESS","CLEANSTACK"], +[["0100","645168",1E-8],"0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL","P2SH,WITNESS","CLEANSTACK"], +[["","645168",1E-8],"0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL","P2SH,WITNESS","OK"], +[["00","645168",1E-8],"0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL","P2SH,WITNESS","OK"], +[["01","645168",1E-8],"0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL","P2SH,WITNESS,MINIMALIF","CLEANSTACK"], +[["02","645168",1E-8],"0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL","P2SH,WITNESS,MINIMALIF","MINIMALIF"], +[["0100","645168",1E-8],"0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL","P2SH,WITNESS,MINIMALIF","MINIMALIF"], +[["","645168",1E-8],"0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL","P2SH,WITNESS,MINIMALIF","OK"], +[["00","645168",1E-8],"0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL","P2SH,WITNESS,MINIMALIF","MINIMALIF"], +[["645168",1E-8],"0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL","P2SH,WITNESS","UNBALANCED_CONDITIONAL"], +[["645168",1E-8],"0x22 0x0020f913eacf2e38a5d6fc3a8311d72ae704cb83866350a984dd3e5eb76d2a8c28e8","HASH160 0x14 0xdbb7d1c0a56b7a9c423300c8cca6e6e065baf1dc EQUAL","P2SH,WITNESS,MINIMALIF","UNBALANCED_CONDITIONAL"], +["0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0","0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT","DERSIG,NULLFAIL","OK","BIP66 and NULLFAIL-compliant"], +["1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0","0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT","DERSIG,NULLFAIL","OK","BIP66 and NULLFAIL-compliant, not NULLDUMMY-compliant"], +["1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0","0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT","DERSIG,NULLFAIL,NULLDUMMY","SIG_NULLDUMMY","BIP66 and NULLFAIL-compliant, not NULLDUMMY-compliant"], +["0 0x09 0x300602010102010101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0","0x01 0x14 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0x01 0x14 CHECKMULTISIG NOT","DERSIG,NULLFAIL","NULLFAIL","BIP66-compliant but not NULLFAIL-compliant"],