use mini_bitcoin_script::engine::execute;
use mini_bitcoin_script::error::ScriptError;
use mini_bitcoin_script::opcode::Opcode;
use mini_bitcoin_script::token::Token;
use mini_bitcoin_script::tokenizer::parse_script;
fn run(bytes: &[u8]) -> Result<bool, ScriptError> {
let tokens = parse_script(bytes)?;
execute(&tokens)
}
fn run_tokens(tokens: &[Token]) -> Result<bool, ScriptError> {
execute(tokens)
}
#[test]
fn op_dup_duplicates_top() {
let tokens = vec![
Token::PushData(vec![0x42]),
Token::Op(Opcode::OpDup),
Token::Op(Opcode::OpEqual),
];
assert!(run_tokens(&tokens).unwrap());
}
#[test]
fn op_drop_removes_top() {
assert!(run(&[0x51, 0x51, 0x75]).unwrap());
}
#[test]
fn op_swap_two_elements() {
let tokens = vec![
Token::PushData(vec![0xaa]),
Token::PushData(vec![0xbb]),
Token::Op(Opcode::OpSwap),
Token::Op(Opcode::OpDrop),
Token::PushData(vec![0xbb]),
Token::Op(Opcode::OpEqual),
];
assert!(run_tokens(&tokens).unwrap());
}
#[test]
fn op_over_copies_second() {
let tokens = vec![
Token::PushData(vec![0xaa]),
Token::PushData(vec![0xbb]),
Token::Op(Opcode::OpOver),
Token::PushData(vec![0xaa]),
Token::Op(Opcode::OpEqual),
];
assert!(run_tokens(&tokens).unwrap());
}
#[test]
fn op_nip_removes_second() {
let tokens = vec![
Token::PushData(vec![0xaa]),
Token::PushData(vec![0xbb]),
Token::Op(Opcode::OpNip),
Token::PushData(vec![0xbb]),
Token::Op(Opcode::OpEqual),
];
assert!(run_tokens(&tokens).unwrap());
}
#[test]
fn op_tuck_inserts_below_second() {
let tokens = vec![
Token::PushData(vec![0xaa]),
Token::PushData(vec![0xbb]),
Token::Op(Opcode::OpTuck),
Token::Op(Opcode::OpDrop),
Token::Op(Opcode::OpDrop),
Token::PushData(vec![0xbb]),
Token::Op(Opcode::OpEqual),
];
assert!(run_tokens(&tokens).unwrap());
}
#[test]
fn op_2dup_duplicates_top_pair() {
let tokens = vec![
Token::PushData(vec![0xaa]),
Token::PushData(vec![0xaa]),
Token::Op(Opcode::Op2Dup),
Token::Op(Opcode::OpEqual), Token::Op(Opcode::OpDrop), Token::Op(Opcode::OpEqual), ];
assert!(run_tokens(&tokens).unwrap());
}
#[test]
fn op_2drop_removes_top_two() {
assert!(run(&[0x51, 0x52, 0x53, 0x6d]).unwrap());
}
#[test]
fn op_depth_pushes_count() {
let tokens = vec![
Token::Op(Opcode::Op1),
Token::Op(Opcode::Op1),
Token::Op(Opcode::Op1),
Token::Op(Opcode::OpDepth),
Token::PushData(vec![0x03]),
Token::Op(Opcode::OpEqual),
];
assert!(run_tokens(&tokens).unwrap());
}
#[test]
fn op_size_pushes_length() {
let tokens = vec![
Token::PushData(vec![0xaa, 0xbb]),
Token::Op(Opcode::OpSize),
Token::PushData(vec![0x02]),
Token::Op(Opcode::OpEqual),
];
assert!(run_tokens(&tokens).unwrap());
}
#[test]
fn op_equal_true() {
assert!(run(&[0x51, 0x51, 0x87]).unwrap());
}
#[test]
fn op_equal_false() {
assert!(!run(&[0x51, 0x52, 0x87]).unwrap());
}
#[test]
fn op_equalverify_pass() {
assert!(run(&[0x51, 0x51, 0x88, 0x51]).unwrap());
}
#[test]
fn op_equalverify_fail() {
let err = run(&[0x51, 0x52, 0x88]).unwrap_err();
assert_eq!(err, ScriptError::VerifyFailed);
}
#[test]
fn op_verify_true() {
assert!(run(&[0x51, 0x69, 0x51]).unwrap());
}
#[test]
fn op_verify_false() {
let err = run(&[0x00, 0x69]).unwrap_err();
assert_eq!(err, ScriptError::VerifyFailed);
}
#[test]
fn op_not_zero_becomes_one() {
assert!(run(&[0x00, 0x91]).unwrap());
}
#[test]
fn op_not_one_becomes_zero() {
assert!(!run(&[0x51, 0x91]).unwrap());
}
#[test]
fn op_not_five_becomes_zero() {
assert!(!run(&[0x55, 0x91]).unwrap());
}
#[test]
fn op_return_aborts() {
let err = run(&[0x6a]).unwrap_err();
assert_eq!(err, ScriptError::OpReturnEncountered);
}
#[test]
fn op_nop_has_no_effect() {
assert!(run(&[0x51, 0x61]).unwrap());
}
#[test]
fn op_sha256_known_vector() {
let expected =
hex_literal::hex!("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
let tokens = vec![
Token::PushData(vec![]), Token::Op(Opcode::OpSha256),
Token::PushData(expected.to_vec()),
Token::Op(Opcode::OpEqual),
];
assert!(run_tokens(&tokens).unwrap());
}
#[test]
fn op_ripemd160_known_vector() {
let expected = hex_literal::hex!("9c1185a5c5e9fc54612808977ee8f548b2258d31");
let tokens = vec![
Token::PushData(vec![]),
Token::Op(Opcode::OpRipemd160),
Token::PushData(expected.to_vec()),
Token::Op(Opcode::OpEqual),
];
assert!(run_tokens(&tokens).unwrap());
}
#[test]
fn op_hash160_known_vector() {
let expected = hex_literal::hex!("b472a266d0bd89c13706a4132ccfb16f7c3b9fcb");
let tokens = vec![
Token::PushData(vec![]),
Token::Op(Opcode::OpHash160),
Token::PushData(expected.to_vec()),
Token::Op(Opcode::OpEqual),
];
assert!(run_tokens(&tokens).unwrap());
}
#[test]
fn op_hash256_known_vector() {
let expected =
hex_literal::hex!("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456");
let tokens = vec![
Token::PushData(vec![]),
Token::Op(Opcode::OpHash256),
Token::PushData(expected.to_vec()),
Token::Op(Opcode::OpEqual),
];
assert!(run_tokens(&tokens).unwrap());
}
#[test]
fn op_checksig_stub_succeeds() {
let tokens = vec![
Token::PushData(vec![0x30; 71]), Token::PushData(vec![0x02; 33]), Token::Op(Opcode::OpCheckSig),
];
assert!(run_tokens(&tokens).unwrap());
}
#[test]
fn empty_token_list_returns_false() {
assert!(!run_tokens(&[]).unwrap());
}
#[test]
fn op1_alone_is_true() {
assert!(run(&[0x51]).unwrap());
}
#[test]
fn op0_alone_is_false() {
assert!(!run(&[0x00]).unwrap());
}
#[test]
fn stack_underflow_dup_empty() {
let err = run(&[0x76]).unwrap_err();
assert_eq!(err, ScriptError::StackUnderflow);
}
#[test]
fn stack_underflow_drop_empty() {
let err = run(&[0x75]).unwrap_err();
assert_eq!(err, ScriptError::StackUnderflow);
}
#[test]
fn stack_underflow_swap_one_item() {
let err = run(&[0x51, 0x7c]).unwrap_err();
assert_eq!(err, ScriptError::StackUnderflow);
}
#[test]
fn stack_underflow_equal_one_item() {
let err = run(&[0x51, 0x87]).unwrap_err();
assert_eq!(err, ScriptError::StackUnderflow);
}
#[test]
fn op_depth_empty_stack() {
assert!(!run(&[0x74]).unwrap());
}
#[test]
fn op_1negate_pushes_0x81() {
let tokens = vec![
Token::Op(Opcode::Op1Negate),
Token::PushData(vec![0x81]),
Token::Op(Opcode::OpEqual),
];
assert!(run_tokens(&tokens).unwrap());
}