#![allow(unused)]
use crate::constants::*;
use crate::crypto::sha3_256;
use crate::crypto::sign_ed25519::{
self as sign, PublicKey, Signature, ED25519_PUBLIC_KEY_LEN, ED25519_SIGNATURE_LEN,
};
use crate::primitives::asset::{Asset, AssetValues, ItemAsset, TokenAmount};
use crate::primitives::druid::DruidExpectation;
use crate::primitives::transaction::*;
use crate::script::interface_ops::*;
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_tx_hash, construct_tx_in_out_signable_hash,
construct_tx_in_signable_asset_hash, construct_tx_in_signable_hash,
};
use bincode::serialize;
use bytes::Bytes;
use hex::encode;
use ring::error;
use std::collections::{BTreeMap, BTreeSet};
use std::thread::current;
use tracing::{debug, error, info, trace};
use super::transaction_utils::construct_p2sh_address;
pub fn tx_is_valid<'a>(
tx: &Transaction,
current_block_number: u64,
is_in_utxo: impl Fn(&OutPoint) -> Option<&'a TxOut> + 'a,
) -> (bool, String) {
let mut tx_ins_spent: AssetValues = Default::default();
debug!("tx: {:?}", tx.outputs);
if tx.outputs.iter().any(|out| {
debug!("out is item: {:?}", out.value.is_item());
debug!("out has drs: {:?}", out.value.get_genesis_hash().is_none());
debug!("out has metadata: {:?}", out.value.get_metadata().is_some());
(out.value.is_item()
&& (out.value.get_genesis_hash().is_none() || out.value.get_metadata().is_some()))
}) {
error!("ON-SPENDING NEEDS EMPTY METADATA AND NON-EMPTY DRS SPECIFICATION");
return (
false,
"On-spending items needs empty metadata and non-empty genesis hash".to_string(),
);
}
if tx.inputs.is_empty() || tx.outputs.is_empty() {
error!("TRANSACTION HAS NO INPUTS OR OUTPUTS");
return (false, "Transaction has no inputs or outputs".to_string());
}
for tx_in in &tx.inputs {
let full_tx_hash = construct_tx_in_out_signable_hash(tx_in, &tx.outputs);
println!("full_tx_hash: {:?}", full_tx_hash);
let tx_out_point = match tx_in.previous_out.as_ref() {
Some(v) => v,
None => {
error!("TRANSACTION DOESN'T CONTAIN PREVIOUS OUTPOINT");
return (
false,
"Transaction doesn't contain previous outpoint".to_string(),
);
}
};
let tx_out = if let Some(tx_out) = is_in_utxo(tx_out_point) {
tx_out
} else {
error!("UTXO DOESN'T CONTAIN THIS TX");
return (
false,
"UTXO doesn't contain this transaction, or the locktime has not expired"
.to_string(),
);
};
if tx_out.locktime > current_block_number {
error!("LOCKTIME NOT MET");
return (false, "Locktime not expired".to_string());
}
let tx_out_pk = tx_out.script_public_key.as_ref();
let tx_out_hash = construct_tx_in_signable_hash(tx_out_point);
let full_tx_hash = construct_tx_in_out_signable_hash(tx_in, &tx.outputs);
debug!("full_tx_hash: {:?}", full_tx_hash);
if let Some(pk) = tx_out_pk {
if !tx_has_valid_p2pkh_sig(&tx_in.script_signature, &full_tx_hash, pk)
&& !tx_has_valid_p2sh_script(&tx_in.script_signature, pk)
{
error!("INVALID SIGNATURE OR SCRIPT TYPE");
return (false, "Invalid signature or script structure".to_string());
}
} else {
return (false, "Previous outpoint has no public key".to_string());
}
let asset = tx_out.value.clone().with_fixed_hash(tx_out_point);
tx_ins_spent.update_add(&asset);
}
debug!(
"txs are valid: {:?}",
tx_outs_are_valid(&tx.outputs, &tx.fees, tx_ins_spent.clone())
);
tx_outs_are_valid(&tx.outputs, &tx.fees, tx_ins_spent)
}
pub fn tx_outs_are_valid(
tx_outs: &[TxOut],
fees: &[TxOut],
tx_ins_spent: AssetValues,
) -> (bool, String) {
let mut tx_outs_spent: AssetValues = Default::default();
for tx_out in tx_outs {
if let Some(addr) = &tx_out.script_public_key {
if !address_has_valid_length(addr) {
trace!("Address has invalid length");
return (false, "Address in output has invalid length".to_string());
}
}
tx_outs_spent.update_add(&tx_out.value);
}
for fee in fees {
if let Some(addr) = &fee.script_public_key {
if !address_has_valid_length(addr) {
trace!("Address has invalid length");
return (false, "Address in fee has invalid length".to_string());
}
}
tx_outs_spent.update_add(&fee.value);
}
match tx_outs_spent.is_equal(&tx_ins_spent) {
true => (true, "".to_string()),
false => {
error!("TXOUTS SPENT DOESN'T MATCH TXINS SPENT");
(false, "TxOuts spent don't match TxIns spent".to_string())
}
}
}
pub fn tx_has_valid_create_script(script: &Script, asset: &Asset) -> bool {
let mut it = script.stack.iter();
let asset_hash = construct_tx_in_signable_asset_hash(asset);
if let Asset::Item(r) = asset {
if !item_has_valid_size(r) {
trace!("Item metadata is too large");
return false;
}
}
if let (
Some(StackEntry::Op(OpCodes::OP_CREATE)),
Some(StackEntry::Num(_)),
Some(StackEntry::Op(OpCodes::OP_DROP)),
Some(StackEntry::Bytes(b)),
Some(StackEntry::Signature(_)),
Some(StackEntry::PubKey(_)),
Some(StackEntry::Op(OpCodes::OP_CHECKSIG)),
None,
) = (
it.next(),
it.next(),
it.next(),
it.next(),
it.next(),
it.next(),
it.next(),
it.next(),
) {
if b == &asset_hash && script.interpret() {
return true;
}
}
trace!("Invalid script for create: {:?}", script.stack,);
false
}
fn tx_has_valid_p2pkh_sig(script: &Script, outpoint_hash: &str, tx_out_pub_key: &str) -> bool {
let mut it = script.stack.iter();
debug!("script: {:?}", script.stack);
if let (
Some(StackEntry::Bytes(b)),
Some(StackEntry::Signature(_)),
Some(StackEntry::PubKey(_)),
Some(StackEntry::Op(OpCodes::OP_DUP)),
Some(StackEntry::Op(
OpCodes::OP_HASH256 | OpCodes::OP_HASH256_V0 | OpCodes::OP_HASH256_TEMP,
)),
Some(StackEntry::Bytes(h)),
Some(StackEntry::Op(OpCodes::OP_EQUALVERIFY)),
Some(StackEntry::Op(OpCodes::OP_CHECKSIG)),
None,
) = (
it.next(),
it.next(),
it.next(),
it.next(),
it.next(),
it.next(),
it.next(),
it.next(),
it.next(),
) {
debug!("b: {:?}, h: {:?}", b, h);
if h == tx_out_pub_key && b == outpoint_hash && script.interpret() {
return true;
}
}
trace!(
"Invalid P2PKH script: {:?} tx_out_pub_key: {}",
script.stack,
tx_out_pub_key
);
false
}
pub fn tx_has_valid_p2sh_script(script: &Script, address: &str) -> bool {
let p2sh_address = construct_p2sh_address(script);
if p2sh_address == address {
return script.interpret();
}
trace!(
"Invalid P2SH script: {:?}, address: {}",
script.stack,
address
);
false
}
fn item_has_valid_size(item: &ItemAsset) -> bool {
if let Some(metadata) = &item.metadata {
return metadata.len() <= MAX_METADATA_BYTES;
}
true
}
fn address_has_valid_length(address: &str) -> bool {
address.len() == 32 || address.len() == 64
}
#[cfg(test)]
mod tests {
use std::vec;
use super::*;
use crate::constants::ITEM_ACCEPT_VAL;
use crate::primitives::asset::Asset;
use crate::primitives::druid::DdeValues;
use crate::primitives::transaction::OutPoint;
use crate::utils::test_utils::generate_tx_with_ins_and_outs_assets;
use crate::utils::transaction_utils::*;
#[test]
fn test_nop() {
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
op_nop(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
let mut v: Vec<StackEntry> = vec![];
op_nop(&mut stack);
assert_eq!(stack.main_stack, v)
}
#[test]
fn test_if() {
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let mut cond_stack = ConditionStack::new();
let mut v: Vec<StackEntry> = vec![];
op_if(&mut stack, &mut cond_stack);
assert_eq!(stack.main_stack, v);
assert_eq!(cond_stack.size, 1);
assert_eq!(cond_stack.first_false_pos, None);
let mut stack = Stack::new();
stack.push(StackEntry::Num(0));
let mut cond_stack = ConditionStack::new();
let mut v: Vec<StackEntry> = vec![];
op_if(&mut stack, &mut cond_stack);
assert_eq!(stack.main_stack, v);
assert_eq!(cond_stack.size, 1);
assert_eq!(cond_stack.first_false_pos, Some(0));
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let mut cond_stack = ConditionStack::new();
cond_stack.size = 1;
cond_stack.first_false_pos = Some(0);
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
op_if(&mut stack, &mut cond_stack);
assert_eq!(stack.main_stack, v);
assert_eq!(cond_stack.size, 2);
assert_eq!(cond_stack.first_false_pos, Some(0));
let mut stack = Stack::new();
stack.push(StackEntry::Bytes(String::new()));
let mut cond_stack = ConditionStack::new();
let b = op_if(&mut stack, &mut cond_stack);
assert!(!b);
let mut stack = Stack::new();
let mut cond_stack = ConditionStack::new();
let b = op_if(&mut stack, &mut cond_stack);
assert!(!b)
}
#[test]
fn test_notif() {
let mut stack = Stack::new();
stack.push(StackEntry::Num(0));
let mut cond_stack = ConditionStack::new();
let mut v: Vec<StackEntry> = vec![];
op_notif(&mut stack, &mut cond_stack);
assert_eq!(stack.main_stack, v);
assert_eq!(cond_stack.size, 1);
assert_eq!(cond_stack.first_false_pos, None);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let mut cond_stack = ConditionStack::new();
let mut v: Vec<StackEntry> = vec![];
op_notif(&mut stack, &mut cond_stack);
assert_eq!(stack.main_stack, v);
assert_eq!(cond_stack.size, 1);
assert_eq!(cond_stack.first_false_pos, Some(0));
let mut stack = Stack::new();
stack.push(StackEntry::Num(0));
let mut cond_stack = ConditionStack::new();
cond_stack.size = 1;
cond_stack.first_false_pos = Some(0);
let mut v: Vec<StackEntry> = vec![StackEntry::Num(0)];
op_notif(&mut stack, &mut cond_stack);
assert_eq!(stack.main_stack, v);
assert_eq!(cond_stack.size, 2);
assert_eq!(cond_stack.first_false_pos, Some(0));
let mut stack = Stack::new();
stack.push(StackEntry::Bytes(String::new()));
let mut cond_stack = ConditionStack::new();
let b = op_notif(&mut stack, &mut cond_stack);
assert!(!b);
let mut stack = Stack::new();
let mut cond_stack = ConditionStack::new();
let b = op_notif(&mut stack, &mut cond_stack);
assert!(!b)
}
#[test]
fn test_else() {
let mut cond_stack = ConditionStack::new();
cond_stack.size = 1;
cond_stack.first_false_pos = None;
op_else(&mut cond_stack);
assert_eq!(cond_stack.size, 1);
assert_eq!(cond_stack.first_false_pos, Some(0));
let mut cond_stack = ConditionStack::new();
cond_stack.size = 1;
cond_stack.first_false_pos = Some(0);
op_else(&mut cond_stack);
assert_eq!(cond_stack.size, 1);
assert_eq!(cond_stack.first_false_pos, None);
let mut cond_stack = ConditionStack::new();
cond_stack.size = 2;
cond_stack.first_false_pos = Some(0);
op_else(&mut cond_stack);
assert_eq!(cond_stack.size, 2);
assert_eq!(cond_stack.first_false_pos, Some(0));
let mut cond_stack = ConditionStack::new();
let b = op_else(&mut cond_stack);
assert!(!b)
}
#[test]
fn test_endif() {
let mut cond_stack = ConditionStack::new();
cond_stack.size = 1;
cond_stack.first_false_pos = None;
op_endif(&mut cond_stack);
assert_eq!(cond_stack.size, 0);
assert_eq!(cond_stack.first_false_pos, None);
let mut cond_stack = ConditionStack::new();
cond_stack.size = 1;
cond_stack.first_false_pos = Some(0);
op_endif(&mut cond_stack);
assert_eq!(cond_stack.size, 0);
assert_eq!(cond_stack.first_false_pos, None);
let mut cond_stack = ConditionStack::new();
cond_stack.size = 2;
cond_stack.first_false_pos = Some(0);
op_endif(&mut cond_stack);
assert_eq!(cond_stack.size, 1);
assert_eq!(cond_stack.first_false_pos, Some(0));
let mut cond_stack = ConditionStack::new();
let b = op_endif(&mut cond_stack);
assert!(!b)
}
#[test]
fn test_verify() {
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let mut v: Vec<StackEntry> = vec![];
op_verify(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(0));
let b = op_verify(&mut stack);
assert!(!b);
let mut stack = Stack::new();
let b = op_verify(&mut stack);
assert!(!b)
}
#[test]
fn test_burn() {
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let b = op_burn(&mut stack);
assert!(!b);
let mut stack = Stack::new();
let b = op_burn(&mut stack);
assert!(!b)
}
#[test]
fn test_toaltstack() {
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let mut v1: Vec<StackEntry> = vec![];
let mut v2: Vec<StackEntry> = vec![StackEntry::Num(1)];
op_toaltstack(&mut stack);
assert_eq!(stack.main_stack, v1);
assert_eq!(stack.alt_stack, v2);
let mut stack = Stack::new();
let b = op_toaltstack(&mut stack);
assert!(!b)
}
#[test]
fn test_fromaltstack() {
let mut stack = Stack::new();
stack.alt_stack.push(StackEntry::Num(1));
let mut v1: Vec<StackEntry> = vec![StackEntry::Num(1)];
let mut v2: Vec<StackEntry> = vec![];
op_fromaltstack(&mut stack);
assert_eq!(stack.main_stack, v1);
assert_eq!(stack.alt_stack, v2);
let mut stack = Stack::new();
let b = op_fromaltstack(&mut stack);
assert!(!b)
}
#[test]
fn test_2drop() {
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![];
op_2drop(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let b = op_2drop(&mut stack);
assert!(!b)
}
#[test]
fn test_2dup() {
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![];
for i in 1..=2 {
v.push(StackEntry::Num(i));
}
for i in 1..=2 {
v.push(StackEntry::Num(i));
}
op_2dup(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let b = op_2dup(&mut stack);
assert!(!b)
}
#[test]
fn test_3dup() {
let mut stack = Stack::new();
for i in 1..=3 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![];
for i in 1..=3 {
v.push(StackEntry::Num(i));
}
for i in 1..=3 {
v.push(StackEntry::Num(i));
}
op_3dup(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let b = op_3dup(&mut stack);
assert!(!b)
}
#[test]
fn test_2over() {
let mut stack = Stack::new();
for i in 1..=4 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![];
for i in 1..=4 {
v.push(StackEntry::Num(i));
}
for i in 1..=2 {
v.push(StackEntry::Num(i));
}
op_2over(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
for i in 1..=3 {
stack.push(StackEntry::Num(i));
}
let b = op_2over(&mut stack);
assert!(!b)
}
#[test]
fn test_2rot() {
let mut stack = Stack::new();
for i in 1..=6 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![];
for i in 3..=6 {
v.push(StackEntry::Num(i));
}
for i in 1..=2 {
v.push(StackEntry::Num(i));
}
op_2rot(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
for i in 1..=5 {
stack.push(StackEntry::Num(i));
}
let b = op_2rot(&mut stack);
assert!(!b)
}
#[test]
fn test_2swap() {
let mut stack = Stack::new();
for i in 1..=4 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![];
for i in 3..=4 {
v.push(StackEntry::Num(i));
}
for i in 1..=2 {
v.push(StackEntry::Num(i));
}
op_2swap(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
for i in 1..=3 {
stack.push(StackEntry::Num(i));
}
let b = op_2swap(&mut stack);
assert!(!b)
}
#[test]
fn test_ifdup() {
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let mut v: Vec<StackEntry> = vec![];
for i in 1..=2 {
v.push(StackEntry::Num(1));
}
op_ifdup(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(0));
let mut v: Vec<StackEntry> = vec![StackEntry::Num(0)];
op_ifdup(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
let b = op_ifdup(&mut stack);
assert!(!b)
}
#[test]
fn test_depth() {
let mut stack = Stack::new();
for i in 1..=4 {
stack.push(StackEntry::Num(1));
}
let mut v: Vec<StackEntry> = vec![];
for i in 1..=4 {
v.push(StackEntry::Num(1));
}
v.push(StackEntry::Num(4));
op_depth(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
let mut v: Vec<StackEntry> = vec![StackEntry::Num(0)];
op_depth(&mut stack);
assert_eq!(stack.main_stack, v)
}
#[test]
fn test_drop() {
let mut stack = Stack::new();
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
let mut v: Vec<StackEntry> = vec![];
op_drop(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
let b = op_drop(&mut stack);
assert!(!b)
}
#[test]
fn test_dup() {
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let mut v: Vec<StackEntry> = vec![];
for i in 1..=2 {
v.push(StackEntry::Num(1));
}
op_dup(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
let b = op_dup(&mut stack);
assert!(!b)
}
#[test]
fn test_nip() {
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(2)];
op_nip(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
let b = op_nip(&mut stack);
assert!(!b)
}
#[test]
fn test_over() {
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![];
for i in 1..=2 {
v.push(StackEntry::Num(i));
}
v.push(StackEntry::Num(1));
op_over(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
let b = op_over(&mut stack);
assert!(!b)
}
#[test]
fn test_pick() {
let mut stack = Stack::new();
for i in 1..=4 {
stack.push(StackEntry::Num(i));
}
stack.push(StackEntry::Num(3));
let mut v: Vec<StackEntry> = vec![];
for i in 1..=4 {
v.push(StackEntry::Num(i));
}
v.push(StackEntry::Num(1));
op_pick(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
for i in 1..=4 {
stack.push(StackEntry::Num(i));
}
stack.push(StackEntry::Num(0));
let mut v: Vec<StackEntry> = vec![];
for i in 1..=4 {
v.push(StackEntry::Num(i));
}
v.push(StackEntry::Num(4));
op_pick(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
let b = op_pick(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
stack.push(StackEntry::Bytes("hello".to_string()));
let b = op_pick(&mut stack);
assert!(!b);
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let b = op_pick(&mut stack);
assert!(!b)
}
#[test]
fn test_roll() {
let mut stack = Stack::new();
for i in 1..=4 {
stack.push(StackEntry::Num(i));
}
stack.push(StackEntry::Num(3));
let mut v: Vec<StackEntry> = vec![];
for i in 2..=4 {
v.push(StackEntry::Num(i));
}
v.push(StackEntry::Num(1));
op_roll(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
for i in 1..=4 {
stack.push(StackEntry::Num(i));
}
stack.push(StackEntry::Num(0));
let mut v: Vec<StackEntry> = vec![];
for i in 1..=4 {
v.push(StackEntry::Num(i));
}
op_roll(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
let b = op_roll(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
stack.push(StackEntry::Bytes("hello".to_string()));
let b = op_roll(&mut stack);
assert!(!b);
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let b = op_roll(&mut stack);
assert!(!b)
}
#[test]
fn test_rot() {
let mut stack = Stack::new();
for i in 1..=3 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![];
for i in 2..=3 {
v.push(StackEntry::Num(i));
}
v.push(StackEntry::Num(1));
op_rot(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let b = op_rot(&mut stack);
assert!(!b)
}
#[test]
fn test_swap() {
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(2), StackEntry::Num(1)];
op_swap(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
let b = op_swap(&mut stack);
assert!(!b)
}
#[test]
fn test_tuck() {
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(2)];
for i in 1..=2 {
v.push(StackEntry::Num(i));
}
op_tuck(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
let b = op_tuck(&mut stack);
assert!(!b)
}
#[test]
fn test_cat() {
let mut stack = Stack::new();
stack.push(StackEntry::Bytes("hello".to_string()));
stack.push(StackEntry::Bytes("world".to_string()));
let mut v: Vec<StackEntry> = vec![StackEntry::Bytes("helloworld".to_string())];
op_cat(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes("hello".to_string()));
stack.push(StackEntry::Bytes("".to_string()));
let mut v: Vec<StackEntry> = vec![StackEntry::Bytes("hello".to_string())];
op_cat(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes("a".to_string()));
let mut s = String::new();
for i in 1..=MAX_SCRIPT_ITEM_SIZE {
s.push('a');
}
stack.push(StackEntry::Bytes(s.to_string()));
let b = op_cat(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes("hello".to_string()));
let b = op_cat(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes("hello".to_string()));
stack.push(StackEntry::Num(1));
let b = op_cat(&mut stack);
assert!(!b)
}
#[test]
fn test_substr() {
let mut stack = Stack::new();
stack.push(StackEntry::Bytes("hello".to_string()));
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Bytes("el".to_string())];
op_substr(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes("hello".to_string()));
for i in 1..=2 {
stack.push(StackEntry::Num(0));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Bytes("".to_string())];
op_substr(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes("hello".to_string()));
stack.push(StackEntry::Num(0));
stack.push(StackEntry::Num(5));
let mut v: Vec<StackEntry> = vec![StackEntry::Bytes("hello".to_string())];
op_substr(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes("hello".to_string()));
stack.push(StackEntry::Num(5));
stack.push(StackEntry::Num(0));
let b = op_substr(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes("hello".to_string()));
stack.push(StackEntry::Num(1));
stack.push(StackEntry::Num(5));
let b = op_substr(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes("hello".to_string()));
stack.push(StackEntry::Num(1));
let b = op_substr(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes("hello".to_string()));
stack.push(StackEntry::Num(1));
stack.push(StackEntry::Num(usize::MAX));
let b = op_substr(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes("hello".to_string()));
stack.push(StackEntry::Num(1));
stack.push(StackEntry::Bytes("".to_string()));
let b = op_substr(&mut stack);
assert!(!b)
}
#[test]
fn test_left() {
let mut stack = Stack::new();
stack.push(StackEntry::Bytes("hello".to_string()));
stack.push(StackEntry::Num(2));
let mut v: Vec<StackEntry> = vec![StackEntry::Bytes("he".to_string())];
op_left(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes("hello".to_string()));
stack.push(StackEntry::Num(0));
let mut v: Vec<StackEntry> = vec![StackEntry::Bytes("".to_string())];
op_left(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes("hello".to_string()));
stack.push(StackEntry::Num(5));
let mut v: Vec<StackEntry> = vec![StackEntry::Bytes("hello".to_string())];
op_left(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes("hello".to_string()));
stack.push(StackEntry::Bytes("".to_string()));
let b = op_left(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes("hello".to_string()));
let b = op_left(&mut stack);
assert!(!b)
}
#[test]
fn test_right() {
let mut stack = Stack::new();
stack.push(StackEntry::Bytes("hello".to_string()));
stack.push(StackEntry::Num(0));
let mut v: Vec<StackEntry> = vec![StackEntry::Bytes("hello".to_string())];
op_right(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes("hello".to_string()));
stack.push(StackEntry::Num(2));
let mut v: Vec<StackEntry> = vec![StackEntry::Bytes("llo".to_string())];
op_right(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes("hello".to_string()));
stack.push(StackEntry::Num(5));
let mut v: Vec<StackEntry> = vec![StackEntry::Bytes("".to_string())];
op_right(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes("hello".to_string()));
stack.push(StackEntry::Bytes("".to_string()));
let b = op_right(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes("hello".to_string()));
let b = op_right(&mut stack);
assert!(!b)
}
#[test]
fn test_size() {
let mut stack = Stack::new();
stack.push(StackEntry::Bytes("hello".to_string()));
let mut v: Vec<StackEntry> =
vec![StackEntry::Bytes("hello".to_string()), StackEntry::Num(5)];
op_size(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes("".to_string()));
let mut v: Vec<StackEntry> = vec![StackEntry::Bytes("".to_string()), StackEntry::Num(0)];
op_size(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
let b = op_size(&mut stack);
assert!(!b);
let mut stack = Stack::new();
let b = op_size(&mut stack);
assert!(!b)
}
#[test]
fn test_invert() {
let mut stack = Stack::new();
stack.push(StackEntry::Num(0));
let mut v: Vec<StackEntry> = vec![StackEntry::Num(usize::MAX)];
op_invert(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
let b = op_invert(&mut stack);
assert!(!b)
}
#[test]
fn test_and() {
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(0)];
op_and(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
let b = op_and(&mut stack);
assert!(!b)
}
#[test]
fn test_or() {
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(3)];
op_or(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
let b = op_or(&mut stack);
assert!(!b)
}
#[test]
fn test_xor() {
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(3)];
op_xor(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(1));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(0)];
op_xor(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
let b = op_xor(&mut stack);
assert!(!b)
}
#[test]
fn test_equal() {
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Bytes("hello".to_string()));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
op_equal(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(0)];
op_equal(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
let b = op_equal(&mut stack);
assert!(!b)
}
#[test]
fn test_equalverify() {
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Bytes("hello".to_string()));
}
let mut v: Vec<StackEntry> = vec![];
op_equalverify(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let b = op_equalverify(&mut stack);
assert!(!b);
let mut stack = Stack::new();
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
let b = op_equalverify(&mut stack);
assert!(!b)
}
#[test]
fn test_1add() {
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let mut v: Vec<StackEntry> = vec![StackEntry::Num(2)];
op_1add(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(usize::MAX));
let b = op_1add(&mut stack);
assert!(!b);
let mut stack = Stack::new();
let b = op_1add(&mut stack);
assert!(!b)
}
#[test]
fn test_1sub() {
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let mut v: Vec<StackEntry> = vec![StackEntry::Num(0)];
op_1sub(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
let mut v: Vec<StackEntry> = vec![StackEntry::Num(0)];
let b = op_1sub(&mut stack);
assert!(!b);
let mut stack = Stack::new();
let b = op_1sub(&mut stack);
assert!(!b)
}
#[test]
fn test_2mul() {
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let mut v: Vec<StackEntry> = vec![StackEntry::Num(2)];
op_2mul(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(usize::MAX));
let b = op_2mul(&mut stack);
assert!(!b);
let mut stack = Stack::new();
let b = op_2mul(&mut stack);
assert!(!b)
}
#[test]
fn test_2div() {
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let mut v: Vec<StackEntry> = vec![StackEntry::Num(0)];
op_2div(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
let b = op_2div(&mut stack);
assert!(!b)
}
#[test]
fn test_not() {
let mut stack = Stack::new();
stack.push(StackEntry::Num(0));
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
op_not(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let mut v: Vec<StackEntry> = vec![StackEntry::Num(0)];
op_not(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
let b = op_not(&mut stack);
assert!(!b)
}
#[test]
fn test_0notequal() {
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
op_0notequal(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(0));
let mut v: Vec<StackEntry> = vec![StackEntry::Num(0)];
op_0notequal(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
let b = op_0notequal(&mut stack);
assert!(!b)
}
#[test]
fn test_add() {
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(3)];
op_add(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
stack.push(StackEntry::Num(usize::MAX));
let b = op_add(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let b = op_add(&mut stack);
assert!(!b)
}
#[test]
fn test_sub() {
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
stack.push(StackEntry::Num(0));
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
op_sub(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(0));
stack.push(StackEntry::Num(1));
let b = op_sub(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let b = op_sub(&mut stack);
assert!(!b)
}
#[test]
fn test_mul() {
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(2)];
op_mul(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(2));
stack.push(StackEntry::Num(usize::MAX));
let b = op_mul(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let b = op_mul(&mut stack);
assert!(!b)
}
#[test]
fn test_div() {
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(0)];
op_div(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
stack.push(StackEntry::Num(0));
let b = op_div(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let b = op_div(&mut stack);
assert!(!b)
}
#[test]
fn test_mod() {
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
op_mod(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
stack.push(StackEntry::Num(0));
let b = op_mod(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let b = op_mod(&mut stack);
assert!(!b)
}
#[test]
fn test_lshift() {
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(4)];
op_lshift(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
stack.push(StackEntry::Num(64));
let b = op_lshift(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let b = op_lshift(&mut stack);
assert!(!b)
}
#[test]
fn test_rshift() {
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(0)];
op_rshift(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
stack.push(StackEntry::Num(64));
let b = op_rshift(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let b = op_rshift(&mut stack);
assert!(!b)
}
#[test]
fn test_booland() {
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
op_booland(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
for i in 0..=1 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(0)];
op_booland(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let b = op_booland(&mut stack);
assert!(!b)
}
#[test]
fn test_boolor() {
let mut stack = Stack::new();
for i in 0..=1 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
op_boolor(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(0));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(0)];
op_boolor(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let b = op_boolor(&mut stack);
assert!(!b)
}
#[test]
fn test_numequal() {
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(1));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
op_numequal(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(0)];
op_numequal(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let b = op_numequal(&mut stack);
assert!(!b)
}
#[test]
fn test_numequalverify() {
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(1));
}
let mut v: Vec<StackEntry> = vec![];
op_numequalverify(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let b = op_numequalverify(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let b = op_numequalverify(&mut stack);
assert!(!b)
}
#[test]
fn test_numnotequal() {
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
op_numnotequal(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(1));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(0)];
op_numnotequal(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let b = op_numnotequal(&mut stack);
assert!(!b)
}
#[test]
fn test_lessthan() {
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
op_lessthan(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(1));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(0)];
op_lessthan(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let b = op_lessthan(&mut stack);
assert!(!b)
}
#[test]
fn test_greaterthan() {
let mut stack = Stack::new();
stack.push(StackEntry::Num(2));
stack.push(StackEntry::Num(1));
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
op_greaterthan(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(1));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(0)];
op_greaterthan(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let b = op_greaterthan(&mut stack);
assert!(!b)
}
#[test]
fn test_lessthanorequal() {
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(1));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
op_lessthanorequal(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(2));
stack.push(StackEntry::Num(1));
let mut v: Vec<StackEntry> = vec![StackEntry::Num(0)];
op_lessthanorequal(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let b = op_lessthanorequal(&mut stack);
assert!(!b)
}
#[test]
fn test_greaterthanorequal() {
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(1));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
op_greaterthanorequal(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(0)];
op_greaterthanorequal(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let b = op_greaterthanorequal(&mut stack);
assert!(!b)
}
#[test]
fn test_min() {
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
op_min(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let b = op_min(&mut stack);
assert!(!b)
}
#[test]
fn test_max() {
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(2)];
op_max(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let b = op_max(&mut stack);
assert!(!b)
}
#[test]
fn test_within() {
let mut stack = Stack::new();
stack.push(StackEntry::Num(2));
stack.push(StackEntry::Num(1));
stack.push(StackEntry::Num(3));
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
op_within(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
for i in 1..=3 {
stack.push(StackEntry::Num(i));
}
let mut v: Vec<StackEntry> = vec![StackEntry::Num(0)];
op_within(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
for i in 1..=2 {
stack.push(StackEntry::Num(i));
}
let b = op_within(&mut stack);
assert!(!b)
}
#[test]
fn test_sha3() {
let (pk, sk) = sign::gen_keypair();
let msg = hex::encode(vec![0, 0, 0]);
let sig = sign::sign_detached(msg.as_bytes(), &sk);
let h = hex::encode(sha3_256::digest(sig.as_ref()));
let mut stack = Stack::new();
stack.push(StackEntry::Signature(sig));
let mut v: Vec<StackEntry> = vec![StackEntry::Bytes(h)];
op_sha3(&mut stack);
assert_eq!(stack.main_stack, v);
let h = hex::encode(sha3_256::digest(pk.as_ref()));
let mut stack = Stack::new();
stack.push(StackEntry::PubKey(pk));
let mut v: Vec<StackEntry> = vec![StackEntry::Bytes(h)];
op_sha3(&mut stack);
assert_eq!(stack.main_stack, v);
let s = "hello".to_string();
let h = hex::encode(sha3_256::digest(s.as_bytes()));
let mut stack = Stack::new();
stack.push(StackEntry::Bytes(s));
let mut v: Vec<StackEntry> = vec![StackEntry::Bytes(h)];
op_sha3(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(1));
let b = op_sha3(&mut stack);
assert!(!b);
let mut stack = Stack::new();
let b = op_sha3(&mut stack);
assert!(!b)
}
#[test]
fn test_hash256() {
let (pk, sk) = sign::gen_keypair();
let mut stack = Stack::new();
stack.push(StackEntry::PubKey(pk));
let mut v: Vec<StackEntry> = vec![StackEntry::Bytes(construct_address(&pk))];
op_hash256(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
let b = op_hash256(&mut stack);
assert!(!b)
}
#[test]
fn test_hash256_v0() {
let (pk, sk) = sign::gen_keypair();
let mut stack = Stack::new();
stack.push(StackEntry::PubKey(pk));
let mut v: Vec<StackEntry> = vec![StackEntry::Bytes(construct_address_v0(&pk))];
op_hash256_v0(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
let b = op_hash256_v0(&mut stack);
assert!(!b)
}
#[test]
fn test_hash256_temp() {
let (pk, sk) = sign::gen_keypair();
let mut stack = Stack::new();
stack.push(StackEntry::PubKey(pk));
let mut v: Vec<StackEntry> = vec![StackEntry::Bytes(construct_address_temp(&pk))];
op_hash256_temp(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
let b = op_hash256_temp(&mut stack);
assert!(!b)
}
#[test]
fn test_checksig() {
let (pk, sk) = sign::gen_keypair();
let msg = hex::encode(vec![0, 0, 0]);
let sig = sign::sign_detached(msg.as_bytes(), &sk);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes(msg));
stack.push(StackEntry::Signature(sig));
stack.push(StackEntry::PubKey(pk));
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
op_checksig(&mut stack);
assert_eq!(stack.main_stack, v);
let msg = hex::encode(vec![0, 0, 1]);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes(msg));
stack.push(StackEntry::Signature(sig));
stack.push(StackEntry::PubKey(pk));
let mut v: Vec<StackEntry> = vec![StackEntry::Num(0)];
op_checksig(&mut stack);
assert_eq!(stack.main_stack, v);
let (pk, sk) = sign::gen_keypair();
let msg = hex::encode(vec![0, 0, 0]);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes(msg));
stack.push(StackEntry::Signature(sig));
stack.push(StackEntry::PubKey(pk));
let mut v: Vec<StackEntry> = vec![StackEntry::Num(0)];
op_checksig(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Signature(sig));
stack.push(StackEntry::PubKey(pk));
let b = op_checksig(&mut stack);
assert!(!b)
}
#[test]
fn test_checksigverify() {
let (pk, sk) = sign::gen_keypair();
let msg = hex::encode(vec![0, 0, 0]);
let sig = sign::sign_detached(msg.as_bytes(), &sk);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes(msg));
stack.push(StackEntry::Signature(sig));
stack.push(StackEntry::PubKey(pk));
let mut v: Vec<StackEntry> = vec![];
op_checksigverify(&mut stack);
assert_eq!(stack.main_stack, v);
let msg = hex::encode(vec![0, 0, 1]);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes(msg));
stack.push(StackEntry::Signature(sig));
stack.push(StackEntry::PubKey(pk));
let b = op_checksigverify(&mut stack);
assert!(!b);
let (pk, sk) = sign::gen_keypair();
let msg = hex::encode(vec![0, 0, 0]);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes(msg));
stack.push(StackEntry::Signature(sig));
stack.push(StackEntry::PubKey(pk));
let b = op_checksigverify(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::Signature(sig));
stack.push(StackEntry::PubKey(pk));
let b = op_checksigverify(&mut stack);
assert!(!b)
}
#[test]
fn test_checkmultisig() {
let (pk1, sk1) = sign::gen_keypair();
let (pk2, sk2) = sign::gen_keypair();
let (pk3, sk3) = sign::gen_keypair();
let msg = hex::encode(vec![0, 0, 0]);
let sig1 = sign::sign_detached(msg.as_bytes(), &sk1);
let sig2 = sign::sign_detached(msg.as_bytes(), &sk2);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes(msg));
stack.push(StackEntry::Signature(sig1));
stack.push(StackEntry::Signature(sig2));
stack.push(StackEntry::Num(2));
stack.push(StackEntry::PubKey(pk1));
stack.push(StackEntry::PubKey(pk2));
stack.push(StackEntry::PubKey(pk3));
stack.push(StackEntry::Num(3));
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
op_checkmultisig(&mut stack);
assert_eq!(stack.main_stack, v);
let msg = hex::encode(vec![0, 0, 0]);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes(msg));
stack.push(StackEntry::Num(0));
stack.push(StackEntry::PubKey(pk1));
stack.push(StackEntry::PubKey(pk2));
stack.push(StackEntry::PubKey(pk3));
stack.push(StackEntry::Num(3));
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
op_checkmultisig(&mut stack);
assert_eq!(stack.main_stack, v);
let msg = hex::encode(vec![0, 0, 0]);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes(msg));
stack.push(StackEntry::Num(0));
stack.push(StackEntry::Num(0));
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
op_checkmultisig(&mut stack);
assert_eq!(stack.main_stack, v);
let msg = hex::encode(vec![0, 0, 0]);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes(msg));
stack.push(StackEntry::Signature(sig1));
stack.push(StackEntry::Num(1));
stack.push(StackEntry::PubKey(pk1));
stack.push(StackEntry::Num(1));
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
op_checkmultisig(&mut stack);
assert_eq!(stack.main_stack, v);
let msg = hex::encode(vec![0, 0, 0]);
let sig3 = sign::sign_detached(msg.as_bytes(), &sk3);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes(msg));
stack.push(StackEntry::Signature(sig3));
stack.push(StackEntry::Signature(sig1));
stack.push(StackEntry::Num(2));
stack.push(StackEntry::PubKey(pk2));
stack.push(StackEntry::PubKey(pk3));
stack.push(StackEntry::PubKey(pk1));
stack.push(StackEntry::Num(3));
let mut v: Vec<StackEntry> = vec![StackEntry::Num(1)];
op_checkmultisig(&mut stack);
assert_eq!(stack.main_stack, v);
let msg = hex::encode(vec![0, 0, 1]);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes(msg));
stack.push(StackEntry::Signature(sig1));
stack.push(StackEntry::Signature(sig2));
stack.push(StackEntry::Num(2));
stack.push(StackEntry::PubKey(pk1));
stack.push(StackEntry::PubKey(pk2));
stack.push(StackEntry::PubKey(pk3));
stack.push(StackEntry::Num(3));
let mut v: Vec<StackEntry> = vec![StackEntry::Num(0)];
op_checkmultisig(&mut stack);
assert_eq!(stack.main_stack, v);
let msg = hex::encode(vec![0, 0, 0]);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes(msg));
stack.push(StackEntry::Signature(sig1));
stack.push(StackEntry::Signature(sig1));
stack.push(StackEntry::Num(2));
stack.push(StackEntry::PubKey(pk1));
stack.push(StackEntry::PubKey(pk2));
stack.push(StackEntry::PubKey(pk3));
stack.push(StackEntry::Num(3));
let mut v: Vec<StackEntry> = vec![StackEntry::Num(0)];
op_checkmultisig(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(MAX_PUB_KEYS_PER_MULTISIG as usize + ONE));
let b = op_checkmultisig(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::PubKey(pk1));
stack.push(StackEntry::PubKey(pk2));
stack.push(StackEntry::Num(3));
let b = op_checkmultisig(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::Num(4));
stack.push(StackEntry::PubKey(pk1));
stack.push(StackEntry::PubKey(pk2));
stack.push(StackEntry::PubKey(pk3));
stack.push(StackEntry::Num(3));
let b = op_checkmultisig(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::Signature(sig1));
stack.push(StackEntry::Num(2));
stack.push(StackEntry::PubKey(pk1));
stack.push(StackEntry::PubKey(pk2));
stack.push(StackEntry::PubKey(pk3));
stack.push(StackEntry::Num(3));
let b = op_checkmultisig(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::Signature(sig1));
stack.push(StackEntry::Signature(sig2));
stack.push(StackEntry::Num(2));
stack.push(StackEntry::PubKey(pk1));
stack.push(StackEntry::PubKey(pk2));
stack.push(StackEntry::PubKey(pk3));
stack.push(StackEntry::Num(3));
let b = op_checkmultisig(&mut stack);
assert!(!b);
}
#[test]
fn test_checkmultisigverify() {
let (pk1, sk1) = sign::gen_keypair();
let (pk2, sk2) = sign::gen_keypair();
let (pk3, sk3) = sign::gen_keypair();
let msg = hex::encode(vec![0, 0, 0]);
let sig1 = sign::sign_detached(msg.as_bytes(), &sk1);
let sig2 = sign::sign_detached(msg.as_bytes(), &sk2);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes(msg));
stack.push(StackEntry::Signature(sig1));
stack.push(StackEntry::Signature(sig2));
stack.push(StackEntry::Num(2));
stack.push(StackEntry::PubKey(pk1));
stack.push(StackEntry::PubKey(pk2));
stack.push(StackEntry::PubKey(pk3));
stack.push(StackEntry::Num(3));
let mut v: Vec<StackEntry> = vec![];
op_checkmultisigverify(&mut stack);
assert_eq!(stack.main_stack, v);
let msg = hex::encode(vec![0, 0, 0]);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes(msg));
stack.push(StackEntry::Num(0));
stack.push(StackEntry::PubKey(pk1));
stack.push(StackEntry::PubKey(pk2));
stack.push(StackEntry::PubKey(pk3));
stack.push(StackEntry::Num(3));
let mut v: Vec<StackEntry> = vec![];
op_checkmultisigverify(&mut stack);
assert_eq!(stack.main_stack, v);
let msg = hex::encode(vec![0, 0, 0]);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes(msg));
stack.push(StackEntry::Num(0));
stack.push(StackEntry::Num(0));
let mut v: Vec<StackEntry> = vec![];
op_checkmultisigverify(&mut stack);
assert_eq!(stack.main_stack, v);
let msg = hex::encode(vec![0, 0, 0]);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes(msg));
stack.push(StackEntry::Signature(sig1));
stack.push(StackEntry::Num(1));
stack.push(StackEntry::PubKey(pk1));
stack.push(StackEntry::Num(1));
let mut v: Vec<StackEntry> = vec![];
op_checkmultisigverify(&mut stack);
assert_eq!(stack.main_stack, v);
let msg = hex::encode(vec![0, 0, 0]);
let sig3 = sign::sign_detached(msg.as_bytes(), &sk3);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes(msg));
stack.push(StackEntry::Signature(sig3));
stack.push(StackEntry::Signature(sig1));
stack.push(StackEntry::Num(2));
stack.push(StackEntry::PubKey(pk2));
stack.push(StackEntry::PubKey(pk3));
stack.push(StackEntry::PubKey(pk1));
stack.push(StackEntry::Num(3));
let mut v: Vec<StackEntry> = vec![];
op_checkmultisigverify(&mut stack);
assert_eq!(stack.main_stack, v);
let msg = hex::encode(vec![0, 0, 1]);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes(msg));
stack.push(StackEntry::Signature(sig1));
stack.push(StackEntry::Signature(sig2));
stack.push(StackEntry::Num(2));
stack.push(StackEntry::PubKey(pk1));
stack.push(StackEntry::PubKey(pk2));
stack.push(StackEntry::PubKey(pk3));
stack.push(StackEntry::Num(3));
let b = op_checkmultisigverify(&mut stack);
assert!(!b);
let msg = hex::encode(vec![0, 0, 0]);
let mut stack = Stack::new();
stack.push(StackEntry::Bytes(msg));
stack.push(StackEntry::Signature(sig1));
stack.push(StackEntry::Signature(sig1));
stack.push(StackEntry::Num(2));
stack.push(StackEntry::PubKey(pk1));
stack.push(StackEntry::PubKey(pk2));
stack.push(StackEntry::PubKey(pk3));
stack.push(StackEntry::Num(3));
op_checkmultisigverify(&mut stack);
assert_eq!(stack.main_stack, v);
let mut stack = Stack::new();
stack.push(StackEntry::Num(MAX_PUB_KEYS_PER_MULTISIG as usize + ONE));
let b = op_checkmultisigverify(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::PubKey(pk1));
stack.push(StackEntry::PubKey(pk2));
stack.push(StackEntry::Num(3));
let b = op_checkmultisigverify(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::Num(4));
stack.push(StackEntry::PubKey(pk1));
stack.push(StackEntry::PubKey(pk2));
stack.push(StackEntry::PubKey(pk3));
stack.push(StackEntry::Num(3));
let b = op_checkmultisigverify(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::Signature(sig1));
stack.push(StackEntry::Num(2));
stack.push(StackEntry::PubKey(pk1));
stack.push(StackEntry::PubKey(pk2));
stack.push(StackEntry::PubKey(pk3));
stack.push(StackEntry::Num(3));
let b = op_checkmultisigverify(&mut stack);
assert!(!b);
let mut stack = Stack::new();
stack.push(StackEntry::Signature(sig1));
stack.push(StackEntry::Signature(sig2));
stack.push(StackEntry::Num(2));
stack.push(StackEntry::PubKey(pk1));
stack.push(StackEntry::PubKey(pk2));
stack.push(StackEntry::PubKey(pk3));
stack.push(StackEntry::Num(3));
let b = op_checkmultisigverify(&mut stack);
assert!(!b);
}
#[test]
fn test_is_valid_script() {
let v = vec![];
let script = Script::from(v);
assert!(script.is_valid());
let v = vec![StackEntry::Bytes("a".repeat(500)); 20];
let script = Script::from(v);
assert!(script.is_valid());
let v = vec![StackEntry::Bytes("a".repeat(500)); 21];
let script = Script::from(v);
assert!(!script.is_valid());
let v = vec![StackEntry::Op(OpCodes::OP_1); MAX_OPS_PER_SCRIPT as usize];
let script = Script::from(v);
assert!(script.is_valid());
let v = vec![StackEntry::Op(OpCodes::OP_1); (MAX_OPS_PER_SCRIPT + 1) as usize];
let script = Script::from(v);
assert!(!script.is_valid());
}
#[test]
fn test_is_valid_stack() {
let v = vec![];
let stack = Stack::from(v);
assert!(stack.is_valid());
let v = vec![StackEntry::Num(1); MAX_STACK_SIZE as usize];
let stack = Stack::from(v);
assert!(stack.is_valid());
let v = vec![StackEntry::Num(1); (MAX_STACK_SIZE + 1) as usize];
let stack = Stack::from(v);
assert!(!stack.is_valid());
}
#[test]
fn test_interpret_script() {
let v = vec![];
let script = Script::from(v);
assert!(script.interpret());
let v = vec![StackEntry::Op(OpCodes::OP_0)];
let script = Script::from(v);
assert!(!script.interpret());
let v = vec![StackEntry::Op(OpCodes::OP_1)];
let script = Script::from(v);
assert!(script.interpret());
let v = vec![
StackEntry::Op(OpCodes::OP_1),
StackEntry::Op(OpCodes::OP_2),
StackEntry::Op(OpCodes::OP_ADD),
StackEntry::Op(OpCodes::OP_3),
StackEntry::Op(OpCodes::OP_EQUAL),
];
let script = Script::from(v);
assert!(script.interpret());
let v = vec![StackEntry::Bytes("a".repeat(500)); 20];
let script = Script::from(v);
assert!(script.interpret());
let v = vec![StackEntry::Bytes("a".repeat(500)); 21];
let script = Script::from(v);
assert!(!script.interpret());
let v = vec![StackEntry::Op(OpCodes::OP_1); MAX_OPS_PER_SCRIPT as usize];
let script = Script::from(v);
assert!(script.interpret());
let v = vec![StackEntry::Op(OpCodes::OP_1); (MAX_OPS_PER_SCRIPT + 1) as usize];
let script = Script::from(v);
assert!(!script.interpret());
let v = vec![StackEntry::Num(1); MAX_STACK_SIZE as usize];
let script = Script::from(v);
assert!(script.interpret());
let v = vec![StackEntry::Num(1); (MAX_STACK_SIZE + 1) as usize];
let script = Script::from(v);
assert!(!script.interpret());
}
#[test]
fn test_conditionals() {
let v = vec![
StackEntry::Op(OpCodes::OP_1),
StackEntry::Op(OpCodes::OP_IF),
StackEntry::Op(OpCodes::OP_2),
StackEntry::Op(OpCodes::OP_ELSE),
StackEntry::Op(OpCodes::OP_3),
StackEntry::Op(OpCodes::OP_ELSE),
StackEntry::Op(OpCodes::OP_0),
StackEntry::Op(OpCodes::OP_ENDIF),
];
let script = Script::from(v);
assert!(!script.interpret());
let v = vec![
StackEntry::Op(OpCodes::OP_1),
StackEntry::Op(OpCodes::OP_IF),
StackEntry::Op(OpCodes::OP_2),
StackEntry::Op(OpCodes::OP_ELSE),
StackEntry::Op(OpCodes::OP_3),
StackEntry::Op(OpCodes::OP_ENDIF),
];
let script = Script::from(v);
assert!(script.interpret());
let v = vec![
StackEntry::Op(OpCodes::OP_1),
StackEntry::Op(OpCodes::OP_IF),
StackEntry::Op(OpCodes::OP_0),
StackEntry::Op(OpCodes::OP_ELSE),
StackEntry::Op(OpCodes::OP_3),
StackEntry::Op(OpCodes::OP_ENDIF),
];
let script = Script::from(v);
assert!(!script.interpret());
let v = vec![
StackEntry::Op(OpCodes::OP_0),
StackEntry::Op(OpCodes::OP_IF),
StackEntry::Op(OpCodes::OP_2),
StackEntry::Op(OpCodes::OP_ELSE),
StackEntry::Op(OpCodes::OP_3),
StackEntry::Op(OpCodes::OP_ENDIF),
];
let script = Script::from(v);
assert!(script.interpret());
let v = vec![
StackEntry::Op(OpCodes::OP_0),
StackEntry::Op(OpCodes::OP_IF),
StackEntry::Op(OpCodes::OP_2),
StackEntry::Op(OpCodes::OP_ELSE),
StackEntry::Op(OpCodes::OP_0),
StackEntry::Op(OpCodes::OP_ENDIF),
];
let script = Script::from(v);
assert!(!script.interpret());
let v = vec![
StackEntry::Op(OpCodes::OP_0),
StackEntry::Op(OpCodes::OP_NOTIF),
StackEntry::Op(OpCodes::OP_2),
StackEntry::Op(OpCodes::OP_ELSE),
StackEntry::Op(OpCodes::OP_0),
StackEntry::Op(OpCodes::OP_ENDIF),
];
let script = Script::from(v);
assert!(script.interpret());
let v = vec![
StackEntry::Op(OpCodes::OP_1),
StackEntry::Op(OpCodes::OP_IF),
StackEntry::Op(OpCodes::OP_0),
StackEntry::Op(OpCodes::OP_ENDIF),
];
let script = Script::from(v);
assert!(!script.interpret());
let v = vec![
StackEntry::Op(OpCodes::OP_1),
StackEntry::Op(OpCodes::OP_IF),
StackEntry::Op(OpCodes::OP_2),
StackEntry::Op(OpCodes::OP_IF),
StackEntry::Op(OpCodes::OP_3),
StackEntry::Op(OpCodes::OP_ELSE),
StackEntry::Op(OpCodes::OP_0),
StackEntry::Op(OpCodes::OP_ENDIF),
StackEntry::Op(OpCodes::OP_ENDIF),
];
let script = Script::from(v);
assert!(script.interpret());
let v = vec![
StackEntry::Op(OpCodes::OP_1),
StackEntry::Op(OpCodes::OP_IF),
StackEntry::Op(OpCodes::OP_0),
StackEntry::Op(OpCodes::OP_IF),
StackEntry::Op(OpCodes::OP_3),
StackEntry::Op(OpCodes::OP_ELSE),
StackEntry::Op(OpCodes::OP_0),
StackEntry::Op(OpCodes::OP_ENDIF),
StackEntry::Op(OpCodes::OP_ENDIF),
];
let script = Script::from(v);
assert!(!script.interpret());
let v = vec![
StackEntry::Op(OpCodes::OP_0),
StackEntry::Op(OpCodes::OP_IF),
StackEntry::Op(OpCodes::OP_2),
StackEntry::Op(OpCodes::OP_IF),
StackEntry::Op(OpCodes::OP_3),
StackEntry::Op(OpCodes::OP_ELSE),
StackEntry::Op(OpCodes::OP_4),
StackEntry::Op(OpCodes::OP_ENDIF),
StackEntry::Op(OpCodes::OP_ELSE),
StackEntry::Op(OpCodes::OP_0),
StackEntry::Op(OpCodes::OP_ENDIF),
];
let script = Script::from(v);
assert!(!script.interpret());
let v = vec![
StackEntry::Op(OpCodes::OP_1),
StackEntry::Op(OpCodes::OP_IF),
StackEntry::Op(OpCodes::OP_1),
];
let script = Script::from(v);
assert!(!script.interpret());
let v = vec![
StackEntry::Op(OpCodes::OP_1),
StackEntry::Op(OpCodes::OP_IF),
StackEntry::Op(OpCodes::OP_1),
StackEntry::Op(OpCodes::OP_ELSE),
StackEntry::Op(OpCodes::OP_3),
];
let script = Script::from(v);
assert!(!script.interpret());
let v = vec![
StackEntry::Op(OpCodes::OP_2),
StackEntry::Op(OpCodes::OP_ELSE),
StackEntry::Op(OpCodes::OP_3),
StackEntry::Op(OpCodes::OP_ENDIF),
];
let script = Script::from(v);
assert!(!script.interpret());
let v = vec![StackEntry::Op(OpCodes::OP_IF)];
let script = Script::from(v);
assert!(!script.interpret());
let v = vec![StackEntry::Op(OpCodes::OP_NOTIF)];
let script = Script::from(v);
assert!(!script.interpret());
let v = vec![StackEntry::Op(OpCodes::OP_ELSE)];
let script = Script::from(v);
assert!(!script.interpret());
let v = vec![StackEntry::Op(OpCodes::OP_ENDIF)];
let script = Script::from(v);
assert!(!script.interpret());
}
#[test]
fn test_burn_script() {
let v = vec![StackEntry::Op(OpCodes::OP_BURN)];
let script = Script::from(v);
assert!(!script.interpret());
}
fn create_multisig_tx_ins(tx_values: Vec<TxConstructor>, m: usize) -> Vec<TxIn> {
let mut tx_ins = Vec::new();
for entry in tx_values {
let mut new_tx_in = TxIn::new();
new_tx_in.script_signature = Script::multisig_validation(
m,
entry.pub_keys.len(),
entry.previous_out.t_hash.clone(),
entry.signatures,
entry.pub_keys,
);
new_tx_in.previous_out = Some(entry.previous_out);
tx_ins.push(new_tx_in);
}
tx_ins
}
fn create_multisig_member_tx_ins(tx_values: Vec<TxConstructor>) -> Vec<TxIn> {
let mut tx_ins = Vec::new();
for entry in tx_values {
let mut new_tx_in = TxIn::new();
new_tx_in.script_signature = Script::member_multisig(
entry.previous_out.t_hash.clone(),
entry.pub_keys[0],
entry.signatures[0],
);
new_tx_in.previous_out = Some(entry.previous_out);
tx_ins.push(new_tx_in);
}
tx_ins
}
#[test]
fn test_pass_create_script_valid() {
let asset = Asset::item(1, None, None);
let asset_hash = construct_tx_in_signable_asset_hash(&asset);
let (pk, sk) = sign::gen_keypair();
let signature = sign::sign_detached(asset_hash.as_bytes(), &sk);
let script = Script::new_create_asset(0, asset_hash, signature, pk);
assert!(tx_has_valid_create_script(&script, &asset));
}
#[test]
fn test_fail_create_item_script_invalid() {
let metadata = String::from_utf8_lossy(&[0; MAX_METADATA_BYTES + 1]).to_string();
let asset = Asset::item(1, None, Some(metadata));
let asset_hash = construct_tx_in_signable_asset_hash(&asset);
let (pk, sk) = sign::gen_keypair();
let signature = sign::sign_detached(asset_hash.as_bytes(), &sk);
let script = Script::new_create_asset(0, asset_hash, signature, pk);
assert!(!tx_has_valid_create_script(&script, &asset));
}
#[test]
fn test_validate_addresses_correctly() {
let (pk, _) = sign::gen_keypair();
let address = construct_address(&pk);
assert!(address_has_valid_length(&address));
assert!(address_has_valid_length(&hex::encode([0; 32])));
assert!(!address_has_valid_length(&hex::encode([0; 64])));
}
#[test]
fn test_pass_member_multisig_valid() {
test_pass_member_multisig_valid_common(None);
}
#[test]
fn test_pass_member_multisig_valid_v0() {
test_pass_member_multisig_valid_common(Some(NETWORK_VERSION_V0));
}
#[test]
fn test_pass_member_multisig_valid_temp() {
test_pass_member_multisig_valid_common(Some(NETWORK_VERSION_TEMP));
}
fn test_pass_member_multisig_valid_common(address_version: Option<u64>) {
let (pk, sk) = sign::gen_keypair();
let t_hash = hex::encode(vec![0, 0, 0]);
let signature = sign::sign_detached(t_hash.as_bytes(), &sk);
let tx_const = TxConstructor {
previous_out: OutPoint::new(t_hash, 0),
signatures: vec![signature],
pub_keys: vec![pk],
address_version,
};
let tx_ins = create_multisig_member_tx_ins(vec![tx_const]);
assert!(&tx_ins[0].clone().script_signature.interpret());
}
#[test]
fn test_fail_member_multisig_invalid() {
test_fail_member_multisig_invalid_common(None);
}
#[test]
fn test_fail_member_multisig_invalid_v0() {
test_fail_member_multisig_invalid_common(Some(NETWORK_VERSION_V0));
}
#[test]
fn test_fail_member_multisig_invalid_temp() {
test_fail_member_multisig_invalid_common(Some(NETWORK_VERSION_TEMP));
}
fn test_fail_member_multisig_invalid_common(address_version: Option<u64>) {
let (_pk, sk) = sign::gen_keypair();
let (pk, _sk) = sign::gen_keypair();
let t_hash = hex::encode(vec![0, 0, 0]);
let signature = sign::sign_detached(t_hash.as_bytes(), &sk);
let tx_const = TxConstructor {
previous_out: OutPoint::new(t_hash, 0),
signatures: vec![signature],
pub_keys: vec![pk],
address_version,
};
let tx_ins = create_multisig_member_tx_ins(vec![tx_const]);
assert!(!&tx_ins[0].clone().script_signature.interpret());
}
#[test]
fn test_pass_p2pkh_sig_valid() {
test_pass_p2pkh_sig_valid_common(None);
}
fn test_pass_p2pkh_sig_valid_common(address_version: Option<u64>) {
let (pk, sk) = sign::gen_keypair();
let outpoint = OutPoint {
t_hash: hex::encode(vec![0, 0, 0]),
n: 0,
};
let mut key_material = BTreeMap::new();
key_material.insert(outpoint.clone(), (pk, sk));
let tx_const = TxConstructor {
previous_out: outpoint,
signatures: vec![],
pub_keys: vec![pk],
address_version,
};
let tx_outs = vec![];
let mut tx_ins = construct_payment_tx_ins(vec![tx_const]);
tx_ins = update_input_signatures(&tx_ins, &tx_outs, &key_material);
let hash_to_sign = construct_tx_in_out_signable_hash(&tx_ins[0], &tx_outs);
let tx_out_pk = construct_address_for(&pk, address_version);
assert!(tx_has_valid_p2pkh_sig(
&tx_ins[0].script_signature,
&hash_to_sign,
&tx_out_pk
));
}
#[test]
fn test_fail_p2pkh_sig_invalid() {
test_fail_p2pkh_sig_invalid_common(None);
}
#[test]
fn test_fail_p2pkh_sig_invalid_v0() {
test_fail_p2pkh_sig_invalid_common(Some(NETWORK_VERSION_V0));
}
fn test_fail_p2pkh_sig_invalid_common(address_version: Option<u64>) {
let (pk, sk) = sign::gen_keypair();
let (second_pk, _s) = sign::gen_keypair();
let outpoint = OutPoint {
t_hash: hex::encode(vec![0, 0, 0]),
n: 0,
};
let hash_to_sign = construct_tx_in_signable_hash(&outpoint);
let signature = sign::sign_detached(hash_to_sign.as_bytes(), &sk);
let tx_const = TxConstructor {
previous_out: outpoint,
signatures: vec![signature],
pub_keys: vec![second_pk],
address_version,
};
let tx_ins = construct_payment_tx_ins(vec![tx_const]);
let tx_out_pk = construct_address(&pk);
assert!(!tx_has_valid_p2pkh_sig(
&tx_ins[0].script_signature,
&hash_to_sign,
&tx_out_pk
));
}
#[test]
fn test_fail_p2pkh_sig_script_empty() {
test_fail_p2pkh_sig_script_empty_common(None);
}
#[test]
fn test_fail_p2pkh_sig_script_empty_v0() {
test_fail_p2pkh_sig_script_empty_common(Some(NETWORK_VERSION_V0));
}
#[test]
fn test_fail_p2pkh_sig_script_empty_temp() {
test_fail_p2pkh_sig_script_empty_common(Some(NETWORK_VERSION_V0));
}
fn test_fail_p2pkh_sig_script_empty_common(address_version: Option<u64>) {
let (pk, sk) = sign::gen_keypair();
let outpoint = OutPoint {
t_hash: hex::encode(vec![0, 0, 0]),
n: 0,
};
let hash_to_sign = construct_tx_in_signable_hash(&outpoint);
let signature = sign::sign_detached(hash_to_sign.as_bytes(), &sk);
let tx_const = TxConstructor {
previous_out: outpoint,
signatures: vec![signature],
pub_keys: vec![pk],
address_version,
};
let mut tx_ins = Vec::new();
for entry in [tx_const] {
let mut new_tx_in = TxIn::new();
new_tx_in.script_signature = Script::new();
new_tx_in.previous_out = Some(entry.previous_out);
tx_ins.push(new_tx_in);
}
let tx_out_pk = construct_address(&pk);
assert!(!tx_has_valid_p2pkh_sig(
&tx_ins[0].script_signature,
&hash_to_sign,
&tx_out_pk
));
}
#[test]
fn test_fail_p2pkh_sig_script_invalid_struct() {
test_fail_p2pkh_sig_script_invalid_struct_common(None);
}
#[test]
fn test_fail_p2pkh_sig_script_invalid_struct_v0() {
test_fail_p2pkh_sig_script_invalid_struct_common(Some(NETWORK_VERSION_V0));
}
#[test]
fn test_fail_p2pkh_sig_script_invalid_struct_temp() {
test_fail_p2pkh_sig_script_invalid_struct_common(Some(NETWORK_VERSION_TEMP));
}
fn test_fail_p2pkh_sig_script_invalid_struct_common(address_version: Option<u64>) {
let (pk, sk) = sign::gen_keypair();
let outpoint = OutPoint {
t_hash: hex::encode(vec![0, 0, 0]),
n: 0,
};
let hash_to_sign = construct_tx_in_signable_hash(&outpoint);
let signature = sign::sign_detached(hash_to_sign.as_bytes(), &sk);
let tx_const = TxConstructor {
previous_out: outpoint,
signatures: vec![signature],
pub_keys: vec![pk],
address_version,
};
let mut tx_ins = Vec::new();
for entry in [tx_const] {
let mut new_tx_in = TxIn::new();
new_tx_in.script_signature = Script::new();
new_tx_in
.script_signature
.stack
.push(StackEntry::Bytes("".to_string()));
new_tx_in.previous_out = Some(entry.previous_out);
tx_ins.push(new_tx_in);
}
let tx_out_pk = construct_address(&pk);
assert!(!tx_has_valid_p2pkh_sig(
&tx_ins[0].script_signature,
&hash_to_sign,
&tx_out_pk
));
}
#[test]
fn test_pass_multisig_validation_valid() {
test_pass_multisig_validation_valid_common(None);
}
#[test]
fn test_pass_multisig_validation_valid_v0() {
test_pass_multisig_validation_valid_common(Some(NETWORK_VERSION_V0));
}
#[test]
fn test_pass_multisig_validation_valid_temp() {
test_pass_multisig_validation_valid_common(Some(NETWORK_VERSION_TEMP));
}
fn test_pass_multisig_validation_valid_common(address_version: Option<u64>) {
let (first_pk, first_sk) = sign::gen_keypair();
let (second_pk, second_sk) = sign::gen_keypair();
let (third_pk, third_sk) = sign::gen_keypair();
let check_data = hex::encode(vec![0, 0, 0]);
let m = 2;
let first_sig = sign::sign_detached(check_data.as_bytes(), &first_sk);
let second_sig = sign::sign_detached(check_data.as_bytes(), &second_sk);
let tx_const = TxConstructor {
previous_out: OutPoint::new(check_data, 0),
signatures: vec![first_sig, second_sig],
pub_keys: vec![first_pk, second_pk, third_pk],
address_version,
};
let tx_ins = create_multisig_tx_ins(vec![tx_const], m);
assert!(&tx_ins[0].script_signature.interpret());
}
#[test]
fn test_tx_is_valid() {
test_tx_is_valid_common(None, OpCodes::OP_HASH256, None, false);
}
#[test]
fn test_tx_is_valid_v0() {
test_tx_is_valid_common(
Some(NETWORK_VERSION_V0),
OpCodes::OP_HASH256_V0,
None,
false,
);
}
#[test]
fn test_tx_is_valid_temp() {
test_tx_is_valid_common(
Some(NETWORK_VERSION_TEMP),
OpCodes::OP_HASH256_TEMP,
None,
false,
);
}
#[test]
fn test_tx_is_invalid_empty() {
let mut tx = Transaction::new();
let tx_out = TxOut {
value: Asset::Token(TokenAmount(0)),
locktime: 0,
script_public_key: Some("".to_string()),
};
tx.outputs.push(tx_out);
let result = tx_is_valid(&tx, 500000000, |_| None);
assert!(!result.0);
assert_eq!(result.1, "Transaction has no inputs or outputs".to_string());
}
#[test]
fn test_tx_is_valid_locktime() {
assert!(
test_tx_is_valid_common(None, OpCodes::OP_HASH256, Some(99), false)
&& !test_tx_is_valid_common(None, OpCodes::OP_HASH256, Some(1000000000), false)
);
}
#[test]
fn test_tx_is_valid_fees() {
test_tx_is_valid_common(None, OpCodes::OP_HASH256, None, true);
}
fn test_tx_is_valid_common(
address_version: Option<u64>,
op_hash256: OpCodes,
locktime: Option<u64>,
with_fees: bool,
) -> bool {
let (pk, sk) = sign::gen_keypair();
let tx_hash = hex::encode(vec![0, 0, 0]);
let tx_outpoint = OutPoint::new(tx_hash, 0);
let script_public_key = construct_address_for(&pk, address_version);
let tx_in_previous_out =
TxOut::new_token_amount(script_public_key.clone(), TokenAmount(5), locktime);
let ongoing_tx_outs = vec![tx_in_previous_out.clone()];
let tx_in = TxIn {
script_signature: Script::new(),
previous_out: Some(tx_outpoint.clone()),
};
let valid_bytes = construct_tx_in_out_signable_hash(&tx_in, &ongoing_tx_outs.clone());
let valid_sig = sign::sign_detached(valid_bytes.as_bytes(), &sk);
let inputs = vec![
(
vec![
StackEntry::Bytes(valid_bytes),
StackEntry::Signature(valid_sig),
StackEntry::PubKey(pk),
StackEntry::Op(OpCodes::OP_DUP),
StackEntry::Op(op_hash256),
StackEntry::Bytes(script_public_key),
StackEntry::Op(OpCodes::OP_EQUALVERIFY),
StackEntry::Op(OpCodes::OP_CHECKSIG),
],
true,
),
(vec![StackEntry::Bytes("".to_string())], false),
];
let mut actual_result = Vec::new();
for (script, _) in &inputs {
let tx_ins = vec![TxIn {
script_signature: Script {
stack: script.clone(),
},
previous_out: Some(tx_outpoint.clone()),
}];
let tx = Transaction {
inputs: tx_ins,
outputs: ongoing_tx_outs.clone(),
..Default::default()
};
let result = tx_is_valid(&tx, 500000000, |v| {
Some(&tx_in_previous_out).filter(|_| v == &tx_outpoint)
});
actual_result.push(result.0);
}
actual_result == inputs.iter().map(|(_, e)| *e).collect::<Vec<bool>>()
}
#[test]
fn test_tx_drs_tokens_only_success() {
test_tx_drs_common(
&[(3, None, None), (2, None, None)],
&[(3, None), (2, None)],
(true, "".to_string()),
);
}
#[test]
fn test_tx_drs_tokens_only_failure_amount_mismatch() {
test_tx_drs_common(
&[(3, None, None), (2, None, None)],
&[(3, None), (3, None)],
(false, "TxOuts spent don't match TxIns spent".to_string()),
);
}
#[test]
fn test_tx_drs_items_only_failure_amount_mismatch() {
test_tx_drs_common(
&[
(3, Some("genesis_hash_1"), None),
(2, Some("genesis_hash_2"), None),
],
&[(3, Some("genesis_hash_1")), (3, Some("genesis_hash_2"))],
(false, "TxOuts spent don't match TxIns spent".to_string()),
);
}
#[test]
fn test_tx_drs_items_only_failure_drs_mismatch() {
test_tx_drs_common(
&[
(3, Some("genesis_hash_1"), None),
(2, Some("genesis_hash_2"), None),
],
&[
(3, Some("genesis_hash_1")),
(2, Some("invalid_genesis_hash")),
],
(false, "TxOuts spent don't match TxIns spent".to_string()),
);
}
#[test]
fn test_tx_drs_items_and_tokens_success() {
test_tx_drs_common(
&[(3, Some("genesis_hash"), None), (2, None, None)],
&[(3, Some("genesis_hash")), (2, None)],
(true, "".to_string()),
);
}
#[test]
fn test_tx_drs_items_and_tokens_failure_amount_mismatch() {
test_tx_drs_common(
&[(3, Some("genesis_hash"), None), (2, None, None)],
&[(2, Some("genesis_hash")), (2, None)],
(false, "TxOuts spent don't match TxIns spent".to_string()),
);
}
#[test]
fn test_tx_drs_items_and_tokens_failure_amount_and_drs_mismatch() {
let test_metadata: Option<String> = Some(
"{\"name\":\"test\",\"description\":\"test\",\"image\":\"test\",\"url\":\"test\"}"
.to_string(),
);
test_tx_drs_common(
&[
(3, Some("genesis_hash"), test_metadata.clone()),
(2, None, test_metadata),
],
&[(1, Some("invalid_genesis_hash")), (1, None)],
(false, "TxOuts spent don't match TxIns spent".to_string()),
);
}
fn test_tx_drs_common(
inputs: &[(u64, Option<&str>, Option<String>)],
outputs: &[(u64, Option<&str>)],
expected_result: (bool, String),
) {
let (utxo, tx) = generate_tx_with_ins_and_outs_assets(inputs, outputs);
let actual_result = tx_is_valid(&tx, 100, |v| utxo.get(v));
assert_eq!(actual_result, expected_result);
}
#[test]
fn test_fail_interpret_valid() {
test_fail_interpret_valid_common(None);
}
#[test]
fn test_fail_interpret_valid_v0() {
test_fail_interpret_valid_common(Some(NETWORK_VERSION_V0));
}
#[test]
fn test_fail_interpret_valid_temp() {
test_fail_interpret_valid_common(Some(NETWORK_VERSION_TEMP));
}
fn test_fail_interpret_valid_common(address_version: Option<u64>) {
let (_pk, sk) = sign::gen_keypair();
let (pk, _sk) = sign::gen_keypair();
let t_hash = hex::encode(vec![0, 0, 0]);
let signature = sign::sign_detached(t_hash.as_bytes(), &sk);
let tx_const = TxConstructor {
previous_out: OutPoint::new(t_hash, 0),
signatures: vec![signature],
pub_keys: vec![pk],
address_version,
};
let tx_ins = create_multisig_member_tx_ins(vec![tx_const]);
assert!(!&tx_ins[0].clone().script_signature.interpret());
}
#[test]
fn test_pass_interpret_valid() {
test_pass_interpret_valid_common(None);
}
#[test]
fn test_pass_interpret_valid_v0() {
test_pass_interpret_valid_common(Some(NETWORK_VERSION_V0));
}
#[test]
fn test_pass_interpret_valid_temp() {
test_pass_interpret_valid_common(Some(NETWORK_VERSION_TEMP));
}
fn test_pass_interpret_valid_common(address_version: Option<u64>) {
let (pk, sk) = sign::gen_keypair();
let t_hash = hex::encode(vec![0, 0, 0]);
let signature = sign::sign_detached(t_hash.as_bytes(), &sk);
let tx_const = TxConstructor {
previous_out: OutPoint::new(t_hash, 0),
signatures: vec![signature],
pub_keys: vec![pk],
address_version,
};
let tx_ins = create_multisig_member_tx_ins(vec![tx_const]);
assert!(&tx_ins[0].clone().script_signature.interpret());
}
}