#![allow(unused)]
use crate::constants::*;
use crate::crypto::sha3_256;
use crate::crypto::sign_ed25519 as sign;
use crate::crypto::sign_ed25519::{PublicKey, Signature};
use crate::primitives::asset::{Asset, TokenAmount};
use crate::primitives::transaction::*;
use crate::script::lang::{ConditionStack, Script, Stack};
use crate::script::{OpCodes, StackEntry};
use crate::utils::error_utils::*;
use crate::utils::transaction_utils::{
construct_address, construct_address_temp, construct_address_v0,
};
use bincode::de;
use bincode::serialize;
use bytes::Bytes;
use hex::encode;
use std::collections::BTreeMap;
use tracing::{debug, error, info, trace};
use tracing_subscriber::field::debug;
pub fn op_nop(stack: &mut Stack) -> bool {
let (op, desc) = (OPNOP, OPNOP_DESC);
trace(op, desc);
true
}
pub fn op_if(stack: &mut Stack, cond_stack: &mut ConditionStack) -> bool {
let (op, desc) = (OPIF, OPIF_DESC);
trace(op, desc);
let cond = if cond_stack.all_true() {
let n = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
n != ZERO
} else {
false
};
cond_stack.push(cond);
true
}
pub fn op_notif(stack: &mut Stack, cond_stack: &mut ConditionStack) -> bool {
let (op, desc) = (OPNOTIF, OPNOTIF_DESC);
trace(op, desc);
let cond = if cond_stack.all_true() {
let n = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
n == ZERO
} else {
false
};
cond_stack.push(cond);
true
}
pub fn op_else(cond_stack: &mut ConditionStack) -> bool {
let (op, desc) = (OPELSE, OPELSE_DESC);
trace(op, desc);
if cond_stack.is_empty() {
error_empty_condition(op);
return false;
}
cond_stack.toggle();
true
}
pub fn op_endif(cond_stack: &mut ConditionStack) -> bool {
let (op, desc) = (OPENDIF, OPENDIF_DESC);
trace(op, desc);
if cond_stack.is_empty() {
error_empty_condition(op);
return false;
}
cond_stack.pop();
true
}
pub fn op_verify(stack: &mut Stack) -> bool {
let (op, desc) = (OPVERIFY, OPVERIFY_DESC);
trace(op, desc);
match stack.pop() {
Some(x) => {
if x == StackEntry::Num(ZERO) {
error_verify(op);
return false;
}
}
_ => {
error_num_items(op);
return false;
}
};
true
}
pub fn op_burn(stack: &mut Stack) -> bool {
let (op, desc) = (OPBURN, OPBURN_DESC);
trace(op, desc);
error_burn(op);
false
}
pub fn op_toaltstack(stack: &mut Stack) -> bool {
let (op, desc) = (OPTOALTSTACK, OPTOALTSTACK_DESC);
trace(op, desc);
match stack.pop() {
Some(x) => stack.alt_stack.push(x),
_ => {
error_num_items(op);
return false;
}
};
true
}
pub fn op_fromaltstack(stack: &mut Stack) -> bool {
let (op, desc) = (OPFROMALTSTACK, OPFROMALTSTACK_DESC);
trace(op, desc);
match stack.alt_stack.pop() {
Some(x) => stack.push(x),
_ => {
error_num_items(op);
return false;
}
};
true
}
pub fn op_2drop(stack: &mut Stack) -> bool {
let (op, desc) = (OP2DROP, OP2DROP_DESC);
trace(op, desc);
let len = stack.main_stack.len();
if len < TWO {
error_num_items(op);
return false;
}
stack.main_stack.drain(len - TWO..);
true
}
pub fn op_2dup(stack: &mut Stack) -> bool {
let (op, desc) = (OP2DUP, OP2DUP_DESC);
trace(op, desc);
let len = stack.main_stack.len();
if len < TWO {
error_num_items(op);
return false;
}
let last_two = stack.main_stack[len - TWO..].to_vec();
stack.main_stack.extend_from_slice(&last_two);
true
}
pub fn op_3dup(stack: &mut Stack) -> bool {
let (op, desc) = (OP3DUP, OP3DUP_DESC);
trace(op, desc);
let len = stack.main_stack.len();
if len < THREE {
error_num_items(op);
return false;
}
let last_three = stack.main_stack[len - THREE..].to_vec();
stack.main_stack.extend_from_slice(&last_three);
true
}
pub fn op_2over(stack: &mut Stack) -> bool {
let (op, desc) = (OP2OVER, OP2OVER_DESC);
trace(op, desc);
let len = stack.main_stack.len();
if len < FOUR {
error_num_items(op);
return false;
}
let items = stack.main_stack[len - FOUR..len - TWO].to_vec();
stack.main_stack.extend_from_slice(&items);
true
}
pub fn op_2rot(stack: &mut Stack) -> bool {
let (op, desc) = (OP2ROT, OP2ROT_DESC);
trace(op, desc);
let len = stack.main_stack.len();
if len < SIX {
error_num_items(op);
return false;
}
let items = stack.main_stack[len - SIX..len - FOUR].to_vec();
stack.main_stack.drain(len - SIX..len - FOUR);
stack.main_stack.extend_from_slice(&items);
true
}
pub fn op_2swap(stack: &mut Stack) -> bool {
let (op, desc) = (OP2SWAP, OP2SWAP_DESC);
trace(op, desc);
let len = stack.main_stack.len();
if len < FOUR {
error_num_items(op);
return false;
}
stack.main_stack.swap(len - FOUR, len - TWO);
stack.main_stack.swap(len - THREE, len - ONE);
true
}
pub fn op_ifdup(stack: &mut Stack) -> bool {
let (op, desc) = (OPIFDUP, OPIFDUP_DESC);
trace(op, desc);
match stack.last() {
Some(x) => {
if x != StackEntry::Num(ZERO) {
stack.push(x);
}
}
_ => {
error_num_items(op);
return false;
}
};
true
}
pub fn op_depth(stack: &mut Stack) -> bool {
let (op, desc) = (OPDEPTH, OPDEPTH_DESC);
trace(op, desc);
stack.push(StackEntry::Num(stack.main_stack.len()))
}
pub fn op_drop(stack: &mut Stack) -> bool {
let (op, desc) = (OPDROP, OPDROP_DESC);
trace(op, desc);
match stack.pop() {
Some(x) => (),
_ => {
error_num_items(op);
return false;
}
};
true
}
pub fn op_dup(stack: &mut Stack) -> bool {
let (op, desc) = (OPDUP, OPDUP_DESC);
trace(op, desc);
match stack.last() {
Some(x) => stack.push(x),
_ => {
error_num_items(op);
return false;
}
};
true
}
pub fn op_nip(stack: &mut Stack) -> bool {
let (op, desc) = (OPNIP, OPNIP_DESC);
trace(op, desc);
let len = stack.main_stack.len();
if len < TWO {
error_num_items(op);
return false;
}
stack.main_stack.remove(len - TWO);
true
}
pub fn op_over(stack: &mut Stack) -> bool {
let (op, desc) = (OPOVER, OPOVER_DESC);
trace(op, desc);
let len = stack.main_stack.len();
if len < TWO {
error_num_items(op);
return false;
}
let x1 = stack.main_stack[len - TWO].clone();
stack.push(x1)
}
pub fn op_pick(stack: &mut Stack) -> bool {
let (op, desc) = (OPPICK, OPPICK_DESC);
trace(op, desc);
let n = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let len = stack.main_stack.len();
if n >= len {
error_item_index(op);
return false;
}
let x = stack.main_stack[len - ONE - n].clone();
stack.push(x)
}
pub fn op_roll(stack: &mut Stack) -> bool {
let (op, desc) = (OPROLL, OPROLL_DESC);
trace(op, desc);
let n = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let len = stack.main_stack.len();
if n >= len {
error_item_index(op);
return false;
}
let x = stack.main_stack[len - ONE - n].clone();
stack.main_stack.remove(len - ONE - n);
stack.push(x)
}
pub fn op_rot(stack: &mut Stack) -> bool {
let (op, desc) = (OPROT, OPROT_DESC);
trace(op, desc);
let len = stack.main_stack.len();
if len < THREE {
error_num_items(op);
return false;
}
stack.main_stack.swap(len - THREE, len - TWO);
stack.main_stack.swap(len - TWO, len - ONE);
true
}
pub fn op_swap(stack: &mut Stack) -> bool {
let (op, desc) = (OPSWAP, OPSWAP_DESC);
trace(op, desc);
let len = stack.main_stack.len();
if len < TWO {
error_num_items(op);
return false;
}
stack.main_stack.swap(len - TWO, len - ONE);
true
}
pub fn op_tuck(stack: &mut Stack) -> bool {
let (op, desc) = (OPTUCK, OPTUCK_DESC);
trace(op, desc);
let len = stack.main_stack.len();
if len < TWO {
error_num_items(op);
return false;
}
let x2 = stack.main_stack[len - ONE].clone();
stack.main_stack.insert(len - TWO, x2);
true
}
pub fn op_cat(stack: &mut Stack) -> bool {
let (op, desc) = (OPCAT, OPCAT_DESC);
trace(op, desc);
let s2 = match stack.pop() {
Some(StackEntry::Bytes(s)) => s,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let s1 = match stack.pop() {
Some(StackEntry::Bytes(s)) => s,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
if s1.len() + s2.len() > MAX_SCRIPT_ITEM_SIZE as usize {
error_item_size(op);
return false;
}
let cat = [s1, s2].join("");
stack.push(StackEntry::Bytes(cat))
}
pub fn op_substr(stack: &mut Stack) -> bool {
let (op, desc) = (OPSUBSTR, OPSUBSTR_DESC);
trace(op, desc);
let n2 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let n1 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let s = match stack.pop() {
Some(StackEntry::Bytes(s)) => s,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
if n1 >= s.len() {
error_item_index(op);
return false;
}
if n2 > s.len() {
error_item_index(op);
return false;
}
if n1 + n2 > s.len() {
error_item_index(op);
return false;
}
let substr = s[n1..n1 + n2].to_string();
stack.push(StackEntry::Bytes(substr))
}
pub fn op_left(stack: &mut Stack) -> bool {
let (op, desc) = (OPLEFT, OPLEFT_DESC);
trace(op, desc);
let n = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let s = match stack.pop() {
Some(StackEntry::Bytes(s)) => s,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
if n >= s.len() {
stack.push(StackEntry::Bytes(s))
} else {
let left = s[..n].to_string();
stack.push(StackEntry::Bytes(left))
}
}
pub fn op_right(stack: &mut Stack) -> bool {
let (op, desc) = (OPRIGHT, OPRIGHT_DESC);
trace(op, desc);
let n = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let s = match stack.pop() {
Some(StackEntry::Bytes(s)) => s,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
if n >= s.len() {
stack.push(StackEntry::Bytes("".to_string()))
} else {
let right = s[n..].to_string();
stack.push(StackEntry::Bytes(right))
}
}
pub fn op_size(stack: &mut Stack) -> bool {
let (op, desc) = (OPSIZE, OPSIZE_DESC);
trace(op, desc);
let s = match stack.last() {
Some(StackEntry::Bytes(s)) => s,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
stack.push(StackEntry::Num(s.len()))
}
pub fn op_invert(stack: &mut Stack) -> bool {
let (op, desc) = (OPINVERT, OPINVERT_DESC);
trace(op, desc);
let n = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
stack.push(StackEntry::Num(!n))
}
pub fn op_and(stack: &mut Stack) -> bool {
let (op, desc) = (OPAND, OPAND_DESC);
trace(op, desc);
let n2 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let n1 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
stack.push(StackEntry::Num(n1 & n2))
}
pub fn op_or(stack: &mut Stack) -> bool {
let (op, desc) = (OPOR, OPOR_DESC);
trace(op, desc);
let n2 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let n1 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
stack.push(StackEntry::Num(n1 | n2))
}
pub fn op_xor(stack: &mut Stack) -> bool {
let (op, desc) = (OPXOR, OPXOR_DESC);
trace(op, desc);
let n2 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let n1 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
stack.push(StackEntry::Num(n1 ^ n2))
}
pub fn op_equal(stack: &mut Stack) -> bool {
let (op, desc) = (OPEQUAL, OPEQUAL_DESC);
trace(op, desc);
let x2 = match stack.pop() {
Some(x) => x,
_ => {
error_num_items(op);
return false;
}
};
let x1 = match stack.pop() {
Some(x) => x,
_ => {
error_num_items(op);
return false;
}
};
if x1 == x2 {
stack.push(StackEntry::Num(ONE))
} else {
stack.push(StackEntry::Num(ZERO))
}
}
pub fn op_equalverify(stack: &mut Stack) -> bool {
let (op, desc) = (OPEQUALVERIFY, OPEQUALVERIFY_DESC);
trace(op, desc);
let x2 = match stack.pop() {
Some(x) => x,
_ => {
error_num_items(op);
return false;
}
};
let x1 = match stack.pop() {
Some(x) => x,
_ => {
error_num_items(op);
return false;
}
};
if x1 != x2 {
error_not_equal_items(op);
return false;
}
true
}
pub fn op_1add(stack: &mut Stack) -> bool {
let (op, desc) = (OP1ADD, OP1ADD_DESC);
trace(op, desc);
let n = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
match n.checked_add(ONE) {
Some(n) => stack.push(StackEntry::Num(n)),
_ => {
error_overflow(op);
false
}
}
}
pub fn op_1sub(stack: &mut Stack) -> bool {
let (op, desc) = (OP1SUB, OP1SUB_DESC);
trace(op, desc);
let n = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
match n.checked_sub(ONE) {
Some(n) => stack.push(StackEntry::Num(n)),
_ => {
error_overflow(op);
false
}
}
}
pub fn op_2mul(stack: &mut Stack) -> bool {
let (op, desc) = (OP2MUL, OP2MUL_DESC);
trace(op, desc);
let n = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
match n.checked_mul(TWO) {
Some(n) => stack.push(StackEntry::Num(n)),
_ => {
error_overflow(op);
false
}
}
}
pub fn op_2div(stack: &mut Stack) -> bool {
let (op, desc) = (OP2DIV, OP2DIV_DESC);
trace(op, desc);
let n = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
stack.push(StackEntry::Num(n / TWO))
}
pub fn op_not(stack: &mut Stack) -> bool {
let (op, desc) = (OPNOT, OPNOT_DESC);
trace(op, desc);
let n = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
if n == ZERO {
stack.push(StackEntry::Num(ONE))
} else {
stack.push(StackEntry::Num(ZERO))
}
}
pub fn op_0notequal(stack: &mut Stack) -> bool {
let (op, desc) = (OP0NOTEQUAL, OP0NOTEQUAL_DESC);
trace(op, desc);
let n = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
if n != ZERO {
stack.push(StackEntry::Num(ONE))
} else {
stack.push(StackEntry::Num(ZERO))
}
}
pub fn op_add(stack: &mut Stack) -> bool {
let (op, desc) = (OPADD, OPADD_DESC);
trace(op, desc);
let n2 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let n1 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
match n1.checked_add(n2) {
Some(n) => stack.push(StackEntry::Num(n)),
_ => {
error_overflow(op);
false
}
}
}
pub fn op_sub(stack: &mut Stack) -> bool {
let (op, desc) = (OPSUB, OPSUB_DESC);
trace(op, desc);
let n2 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let n1 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
match n1.checked_sub(n2) {
Some(n) => stack.push(StackEntry::Num(n)),
_ => {
error_overflow(op);
false
}
}
}
pub fn op_mul(stack: &mut Stack) -> bool {
let (op, desc) = (OPMUL, OPMUL_DESC);
trace(op, desc);
let n2 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let n1 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
match n1.checked_mul(n2) {
Some(n) => stack.push(StackEntry::Num(n)),
_ => {
error_overflow(op);
false
}
}
}
pub fn op_div(stack: &mut Stack) -> bool {
let (op, desc) = (OPDIV, OPDIV_DESC);
trace(op, desc);
let n2 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let n1 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
match n1.checked_div(n2) {
Some(n) => stack.push(StackEntry::Num(n)),
_ => {
error_div_zero(op);
false
}
}
}
pub fn op_mod(stack: &mut Stack) -> bool {
let (op, desc) = (OPMOD, OPMOD_DESC);
trace(op, desc);
let n2 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let n1 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
match n1.checked_rem(n2) {
Some(n) => stack.push(StackEntry::Num(n)),
_ => {
error_div_zero(op);
false
}
}
}
pub fn op_lshift(stack: &mut Stack) -> bool {
let (op, desc) = (OPLSHIFT, OPLSHIFT_DESC);
trace(op, desc);
let n2 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let n1 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
match n1.checked_shl(n2 as u32) {
Some(n) => stack.push(StackEntry::Num(n)),
_ => {
error_div_zero(op);
false
}
}
}
pub fn op_rshift(stack: &mut Stack) -> bool {
let (op, desc) = (OPRIGHT, OPRIGHT_DESC);
trace(op, desc);
let n2 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let n1 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
match n1.checked_shr(n2 as u32) {
Some(n) => stack.push(StackEntry::Num(n)),
_ => {
error_div_zero(op);
false
}
}
}
pub fn op_booland(stack: &mut Stack) -> bool {
let (op, desc) = (OPBOOLAND, OPBOOLAND_DESC);
trace(op, desc);
let n2 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let n1 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
if n1 != ZERO && n2 != ZERO {
stack.push(StackEntry::Num(ONE))
} else {
stack.push(StackEntry::Num(ZERO))
}
}
pub fn op_boolor(stack: &mut Stack) -> bool {
let (op, desc) = (OPBOOLOR, OPBOOLOR_DESC);
trace(op, desc);
let n2 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let n1 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
if n1 != ZERO || n2 != ZERO {
stack.push(StackEntry::Num(ONE))
} else {
stack.push(StackEntry::Num(ZERO))
}
}
pub fn op_numequal(stack: &mut Stack) -> bool {
let (op, desc) = (OPNUMEQUAL, OPNUMEQUAL_DESC);
trace(op, desc);
let n2 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let n1 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
if n1 == n2 {
stack.push(StackEntry::Num(ONE))
} else {
stack.push(StackEntry::Num(ZERO))
}
}
pub fn op_numequalverify(stack: &mut Stack) -> bool {
let (op, desc) = (OPNUMEQUALVERIFY, OPNUMEQUALVERIFY_DESC);
trace(op, desc);
let n2 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let n1 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
if n1 != n2 {
error_not_equal_items(op);
return false;
}
true
}
pub fn op_numnotequal(stack: &mut Stack) -> bool {
let (op, desc) = (OPNUMNOTEQUAL, OPNUMNOTEQUAL_DESC);
trace(op, desc);
let n2 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let n1 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
if n1 != n2 {
stack.push(StackEntry::Num(ONE))
} else {
stack.push(StackEntry::Num(ZERO))
}
}
pub fn op_lessthan(stack: &mut Stack) -> bool {
let (op, desc) = (OPLESSTHAN, OPLESSTHAN_DESC);
trace(op, desc);
let n2 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let n1 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
if n1 < n2 {
stack.push(StackEntry::Num(ONE))
} else {
stack.push(StackEntry::Num(ZERO))
}
}
pub fn op_greaterthan(stack: &mut Stack) -> bool {
let (op, desc) = (OP0NOTEQUAL, OP0NOTEQUAL_DESC);
trace(op, desc);
let n2 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let n1 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
if n1 > n2 {
stack.push(StackEntry::Num(ONE))
} else {
stack.push(StackEntry::Num(ZERO))
}
}
pub fn op_lessthanorequal(stack: &mut Stack) -> bool {
let (op, desc) = (OPLESSTHANOREQUAL, OPLESSTHANOREQUAL_DESC);
trace(op, desc);
let n2 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let n1 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
if n1 <= n2 {
stack.push(StackEntry::Num(ONE))
} else {
stack.push(StackEntry::Num(ZERO))
}
}
pub fn op_greaterthanorequal(stack: &mut Stack) -> bool {
let (op, desc) = (OPGREATERTHANOREQUAL, OPGREATERTHANOREQUAL_DESC);
trace(op, desc);
let n2 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let n1 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
if n1 >= n2 {
stack.push(StackEntry::Num(ONE))
} else {
stack.push(StackEntry::Num(ZERO))
}
}
pub fn op_min(stack: &mut Stack) -> bool {
let (op, desc) = (OPMIN, OPMIN_DESC);
trace(op, desc);
let n2 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let n1 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
stack.push(StackEntry::Num(n1.min(n2)))
}
pub fn op_max(stack: &mut Stack) -> bool {
let (op, desc) = (OPMAX, OPMAX_DESC);
trace(op, desc);
let n2 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let n1 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
stack.push(StackEntry::Num(n1.max(n2)))
}
pub fn op_within(stack: &mut Stack) -> bool {
let (op, desc) = (OPWITHIN, OPWITHIN_DESC);
trace(op, desc);
let n3 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let n2 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let n1 = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
if n1 >= n2 && n1 < n3 {
stack.push(StackEntry::Num(ONE))
} else {
stack.push(StackEntry::Num(ZERO))
}
}
pub fn op_sha3(stack: &mut Stack) -> bool {
let (op, desc) = (OPSHA3, OPSHA3_DESC);
trace(op, desc);
let data = match stack.pop() {
Some(StackEntry::Signature(sig)) => sig.as_ref().to_owned(),
Some(StackEntry::PubKey(pk)) => pk.as_ref().to_owned(),
Some(StackEntry::Bytes(s)) => s.as_bytes().to_owned(),
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let hash = hex::encode(sha3_256::digest(&data));
stack.push(StackEntry::Bytes(hash))
}
pub fn op_hash256(stack: &mut Stack) -> bool {
let (op, desc) = (OPHASH256, OPHASH256_DESC);
trace(op, desc);
let pk = match stack.pop() {
Some(StackEntry::PubKey(pk)) => pk,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let addr = construct_address(&pk);
stack.push(StackEntry::Bytes(addr))
}
pub fn op_hash256_v0(stack: &mut Stack) -> bool {
let (op, desc) = (OPHASH256V0, OPHASH256V0_DESC);
trace(op, desc);
let pk = match stack.pop() {
Some(StackEntry::PubKey(pk)) => pk,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let addr_v0 = construct_address_v0(&pk);
stack.push(StackEntry::Bytes(addr_v0))
}
pub fn op_hash256_temp(stack: &mut Stack) -> bool {
let (op, desc) = (OPHASH256TEMP, OPHASH256TEMP_DESC);
trace(op, desc);
let pk = match stack.pop() {
Some(StackEntry::PubKey(pk)) => pk,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let addr_temp = construct_address_temp(&pk);
stack.push(StackEntry::Bytes(addr_temp))
}
pub fn op_checksig(stack: &mut Stack) -> bool {
let (op, desc) = (OPCHECKSIG, OPCHECKSIG_DESC);
trace(op, desc);
let pk = match stack.pop() {
Some(StackEntry::PubKey(pk)) => pk,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let sig = match stack.pop() {
Some(StackEntry::Signature(sig)) => sig,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let msg = match stack.pop() {
Some(StackEntry::Bytes(s)) => s,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
trace!("Signature: {:?}", hex::encode(sig));
if (!sign::verify_detached(&sig, msg.as_bytes(), &pk)) {
trace!("Signature verification failed");
stack.push(StackEntry::Num(ZERO))
} else {
trace!("Signature verification succeeded");
stack.push(StackEntry::Num(ONE))
}
}
pub fn op_checksigverify(stack: &mut Stack) -> bool {
let (op, desc) = (OPCHECKSIGVERIFY, OPCHECKSIGVERIFY_DESC);
trace(op, desc);
let pk = match stack.pop() {
Some(StackEntry::PubKey(pk)) => pk,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let sig = match stack.pop() {
Some(StackEntry::Signature(sig)) => sig,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
let msg = match stack.pop() {
Some(StackEntry::Bytes(s)) => s,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
trace!("Signature: {:?}", hex::encode(sig));
if (!sign::verify_detached(&sig, msg.as_bytes(), &pk)) {
trace!("Signature verification failed");
error_invalid_signature(op);
return false;
}
true
}
pub fn op_checkmultisig(stack: &mut Stack) -> bool {
let (op, desc) = (OPCHECKMULTISIG, OPCHECKMULTISIG_DESC);
trace(op, desc);
let n = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
if n > MAX_PUB_KEYS_PER_MULTISIG as usize {
error_num_pubkeys(op);
return false;
}
let mut pks = Vec::new();
while let Some(StackEntry::PubKey(_)) = stack.last() {
if let Some(StackEntry::PubKey(pk)) = stack.pop() {
pks.push(pk);
}
}
if pks.len() != n {
error_num_pubkeys(op);
return false;
}
let m = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
if m > n {
error_num_signatures(op);
return false;
}
let mut sigs = Vec::new();
while let Some(StackEntry::Signature(_)) = stack.last() {
if let Some(StackEntry::Signature(sig)) = stack.pop() {
sigs.push(sig);
}
}
if sigs.len() != m {
error_num_signatures(op);
return false;
}
let msg = match stack.pop() {
Some(StackEntry::Bytes(s)) => s,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
if !verify_multisig(&sigs, &msg, &mut pks) {
stack.push(StackEntry::Num(ZERO))
} else {
stack.push(StackEntry::Num(ONE))
}
}
pub fn op_checkmultisigverify(stack: &mut Stack) -> bool {
let (op, desc) = (OPCHECKMULTISIG, OPCHECKMULTISIG_DESC);
trace(op, desc);
let n = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
if n > MAX_PUB_KEYS_PER_MULTISIG as usize {
error_num_pubkeys(op);
return false;
}
let mut pks = Vec::new();
while let Some(StackEntry::PubKey(_)) = stack.last() {
if let Some(StackEntry::PubKey(pk)) = stack.pop() {
pks.push(pk);
}
}
if pks.len() != n {
error_num_pubkeys(op);
return false;
}
let m = match stack.pop() {
Some(StackEntry::Num(n)) => n,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
if m > n {
error_num_signatures(op);
return false;
}
let mut sigs = Vec::new();
while let Some(StackEntry::Signature(_)) = stack.last() {
if let Some(StackEntry::Signature(sig)) = stack.pop() {
sigs.push(sig);
}
}
if sigs.len() != m {
error_num_signatures(op);
return false;
}
let msg = match stack.pop() {
Some(StackEntry::Bytes(s)) => s,
Some(_) => {
error_item_type(op);
return false;
}
_ => {
error_num_items(op);
return false;
}
};
if !verify_multisig(&sigs, &msg, &mut pks) {
error_invalid_multisignature(op);
return false;
}
true
}
fn verify_multisig(sigs: &[Signature], msg: &String, pks: &mut Vec<PublicKey>) -> bool {
let mut num_valid_sigs = ZERO;
for sig in sigs {
if let Some((index, _)) = pks
.iter()
.enumerate()
.find(|(_, pk)| sign::verify_detached(sig, msg.as_bytes(), pk))
{
num_valid_sigs += ONE;
pks.remove(index);
}
}
num_valid_sigs == sigs.len()
}