601 lines
17 KiB
Rust
601 lines
17 KiB
Rust
#![allow(non_camel_case_types)]
|
|
|
|
use std::{
|
|
num::TryFromIntError,
|
|
ops::{Add, Neg, Sub},
|
|
};
|
|
|
|
use enum_primitive::FromPrimitive;
|
|
|
|
use super::script_error::*;
|
|
|
|
pub const MAX_SCRIPT_ELEMENT_SIZE: usize = 520; // bytes
|
|
|
|
/// Maximum script length in bytes
|
|
pub const MAX_SCRIPT_SIZE: usize = 10000;
|
|
|
|
// Threshold for lock_time: below this value it is interpreted as block number,
|
|
// otherwise as UNIX timestamp.
|
|
pub const LOCKTIME_THRESHOLD: ScriptNum = ScriptNum(500000000); // Tue Nov 5 00:53:20 1985 UTC
|
|
|
|
/** Script opcodes */
|
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
|
pub enum Opcode {
|
|
PushValue(PushValue),
|
|
Operation(Operation),
|
|
}
|
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
|
#[repr(u8)]
|
|
pub enum PushValue {
|
|
// push value
|
|
OP_0 = 0x00,
|
|
PushdataBytelength(u8),
|
|
OP_PUSHDATA1 = 0x4c,
|
|
OP_PUSHDATA2 = 0x4d,
|
|
OP_PUSHDATA4 = 0x4e,
|
|
OP_1NEGATE = 0x4f,
|
|
OP_RESERVED = 0x50,
|
|
OP_1 = 0x51,
|
|
OP_2 = 0x52,
|
|
OP_3 = 0x53,
|
|
OP_4 = 0x54,
|
|
OP_5 = 0x55,
|
|
OP_6 = 0x56,
|
|
OP_7 = 0x57,
|
|
OP_8 = 0x58,
|
|
OP_9 = 0x59,
|
|
OP_10 = 0x5a,
|
|
OP_11 = 0x5b,
|
|
OP_12 = 0x5c,
|
|
OP_13 = 0x5d,
|
|
OP_14 = 0x5e,
|
|
OP_15 = 0x5f,
|
|
OP_16 = 0x60,
|
|
}
|
|
|
|
use PushValue::*;
|
|
|
|
enum_from_primitive! {
|
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
|
#[repr(u8)]
|
|
pub enum Operation {
|
|
// control
|
|
OP_NOP = 0x61,
|
|
OP_VER = 0x62,
|
|
OP_IF = 0x63,
|
|
OP_NOTIF = 0x64,
|
|
OP_VERIF = 0x65,
|
|
OP_VERNOTIF = 0x66,
|
|
OP_ELSE = 0x67,
|
|
OP_ENDIF = 0x68,
|
|
OP_VERIFY = 0x69,
|
|
OP_RETURN = 0x6a,
|
|
|
|
// stack ops
|
|
OP_TOALTSTACK = 0x6b,
|
|
OP_FROMALTSTACK = 0x6c,
|
|
OP_2DROP = 0x6d,
|
|
OP_2DUP = 0x6e,
|
|
OP_3DUP = 0x6f,
|
|
OP_2OVER = 0x70,
|
|
OP_2ROT = 0x71,
|
|
OP_2SWAP = 0x72,
|
|
OP_IFDUP = 0x73,
|
|
OP_DEPTH = 0x74,
|
|
OP_DROP = 0x75,
|
|
OP_DUP = 0x76,
|
|
OP_NIP = 0x77,
|
|
OP_OVER = 0x78,
|
|
OP_PICK = 0x79,
|
|
OP_ROLL = 0x7a,
|
|
OP_ROT = 0x7b,
|
|
OP_SWAP = 0x7c,
|
|
OP_TUCK = 0x7d,
|
|
|
|
// splice ops
|
|
OP_CAT = 0x7e,
|
|
OP_SUBSTR = 0x7f,
|
|
OP_LEFT = 0x80,
|
|
OP_RIGHT = 0x81,
|
|
OP_SIZE = 0x82,
|
|
|
|
// bit logic
|
|
OP_INVERT = 0x83,
|
|
OP_AND = 0x84,
|
|
OP_OR = 0x85,
|
|
OP_XOR = 0x86,
|
|
OP_EQUAL = 0x87,
|
|
OP_EQUALVERIFY = 0x88,
|
|
OP_RESERVED1 = 0x89,
|
|
OP_RESERVED2 = 0x8a,
|
|
|
|
// numeric
|
|
OP_1ADD = 0x8b,
|
|
OP_1SUB = 0x8c,
|
|
OP_2MUL = 0x8d,
|
|
OP_2DIV = 0x8e,
|
|
OP_NEGATE = 0x8f,
|
|
OP_ABS = 0x90,
|
|
OP_NOT = 0x91,
|
|
OP_0NOTEQUAL = 0x92,
|
|
|
|
OP_ADD = 0x93,
|
|
OP_SUB = 0x94,
|
|
OP_MUL = 0x95,
|
|
OP_DIV = 0x96,
|
|
OP_MOD = 0x97,
|
|
OP_LSHIFT = 0x98,
|
|
OP_RSHIFT = 0x99,
|
|
|
|
OP_BOOLAND = 0x9a,
|
|
OP_BOOLOR = 0x9b,
|
|
OP_NUMEQUAL = 0x9c,
|
|
OP_NUMEQUALVERIFY = 0x9d,
|
|
OP_NUMNOTEQUAL = 0x9e,
|
|
OP_LESSTHAN = 0x9f,
|
|
OP_GREATERTHAN = 0xa0,
|
|
OP_LESSTHANOREQUAL = 0xa1,
|
|
OP_GREATERTHANOREQUAL = 0xa2,
|
|
OP_MIN = 0xa3,
|
|
OP_MAX = 0xa4,
|
|
|
|
OP_WITHIN = 0xa5,
|
|
|
|
// crypto
|
|
OP_RIPEMD160 = 0xa6,
|
|
OP_SHA1 = 0xa7,
|
|
OP_SHA256 = 0xa8,
|
|
OP_HASH160 = 0xa9,
|
|
OP_HASH256 = 0xaa,
|
|
OP_CODESEPARATOR = 0xab,
|
|
OP_CHECKSIG = 0xac,
|
|
OP_CHECKSIGVERIFY = 0xad,
|
|
OP_CHECKMULTISIG = 0xae,
|
|
OP_CHECKMULTISIGVERIFY = 0xaf,
|
|
|
|
// expansion
|
|
OP_NOP1 = 0xb0,
|
|
OP_CHECKLOCKTIMEVERIFY = 0xb1,
|
|
OP_NOP3 = 0xb2,
|
|
OP_NOP4 = 0xb3,
|
|
OP_NOP5 = 0xb4,
|
|
OP_NOP6 = 0xb5,
|
|
OP_NOP7 = 0xb6,
|
|
OP_NOP8 = 0xb7,
|
|
OP_NOP9 = 0xb8,
|
|
OP_NOP10 = 0xb9,
|
|
|
|
OP_INVALIDOPCODE = 0xff,
|
|
}
|
|
}
|
|
|
|
use Operation::*;
|
|
|
|
impl From<Opcode> for u8 {
|
|
fn from(value: Opcode) -> Self {
|
|
match value {
|
|
Opcode::PushValue(pv) => pv.into(),
|
|
Opcode::Operation(op) => op.into(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<u8> for Opcode {
|
|
fn from(value: u8) -> Self {
|
|
Operation::from_u8(value).map_or(
|
|
PushValue::try_from(value)
|
|
.map_or(Opcode::Operation(OP_INVALIDOPCODE), Opcode::PushValue),
|
|
Opcode::Operation,
|
|
)
|
|
}
|
|
}
|
|
|
|
impl From<PushValue> for u8 {
|
|
fn from(value: PushValue) -> Self {
|
|
match value {
|
|
OP_0 => 0x00,
|
|
PushdataBytelength(byte) => byte,
|
|
OP_PUSHDATA1 => 0x4c,
|
|
OP_PUSHDATA2 => 0x4d,
|
|
OP_PUSHDATA4 => 0x4e,
|
|
OP_1NEGATE => 0x4f,
|
|
OP_RESERVED => 0x50,
|
|
OP_1 => 0x51,
|
|
OP_2 => 0x52,
|
|
OP_3 => 0x53,
|
|
OP_4 => 0x54,
|
|
OP_5 => 0x55,
|
|
OP_6 => 0x56,
|
|
OP_7 => 0x57,
|
|
OP_8 => 0x58,
|
|
OP_9 => 0x59,
|
|
OP_10 => 0x5a,
|
|
OP_11 => 0x5b,
|
|
OP_12 => 0x5c,
|
|
OP_13 => 0x5d,
|
|
OP_14 => 0x5e,
|
|
OP_15 => 0x5f,
|
|
OP_16 => 0x60,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<u8> for PushValue {
|
|
type Error = ();
|
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
|
match value {
|
|
0x00 => Ok(OP_0),
|
|
0x4c => Ok(OP_PUSHDATA1),
|
|
0x4d => Ok(OP_PUSHDATA2),
|
|
0x4e => Ok(OP_PUSHDATA4),
|
|
0x4f => Ok(OP_1NEGATE),
|
|
0x50 => Ok(OP_RESERVED),
|
|
0x51 => Ok(OP_1),
|
|
0x52 => Ok(OP_2),
|
|
0x53 => Ok(OP_3),
|
|
0x54 => Ok(OP_4),
|
|
0x55 => Ok(OP_5),
|
|
0x56 => Ok(OP_6),
|
|
0x57 => Ok(OP_7),
|
|
0x58 => Ok(OP_8),
|
|
0x59 => Ok(OP_9),
|
|
0x5a => Ok(OP_10),
|
|
0x5b => Ok(OP_11),
|
|
0x5c => Ok(OP_12),
|
|
0x5d => Ok(OP_13),
|
|
0x5e => Ok(OP_14),
|
|
0x5f => Ok(OP_15),
|
|
0x60 => Ok(OP_16),
|
|
_ => {
|
|
if value <= 0x60 {
|
|
Ok(PushdataBytelength(value))
|
|
} else {
|
|
Err(())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Operation> for u8 {
|
|
fn from(value: Operation) -> Self {
|
|
// This is how you get the discriminant, but using `as` everywhere is too much code smell
|
|
value as u8
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
|
pub struct ScriptNum(i64);
|
|
|
|
impl ScriptNum {
|
|
pub const ZERO: ScriptNum = ScriptNum(0);
|
|
pub const ONE: ScriptNum = ScriptNum(1);
|
|
|
|
const DEFAULT_MAX_NUM_SIZE: usize = 4;
|
|
|
|
pub fn new(
|
|
vch: &Vec<u8>,
|
|
require_minimal: bool,
|
|
max_num_size: Option<usize>,
|
|
) -> Result<Self, ScriptNumError> {
|
|
let max_num_size = max_num_size.unwrap_or(Self::DEFAULT_MAX_NUM_SIZE);
|
|
if vch.len() > max_num_size {
|
|
return Err(ScriptNumError::Overflow {
|
|
max_num_size,
|
|
actual: vch.len(),
|
|
});
|
|
}
|
|
if require_minimal && !vch.is_empty() {
|
|
// Check that the number is encoded with the minimum possible
|
|
// number of bytes.
|
|
//
|
|
// If the most-significant-byte - excluding the sign bit - is zero
|
|
// then we're not minimal. Note how this test also rejects the
|
|
// negative-zero encoding, 0x80.
|
|
if (vch.last().expect("not empty") & 0x7F) == 0 {
|
|
// One exception: if there's more than one byte and the most
|
|
// significant bit of the second-most-significant-byte is set
|
|
// then it would have conflicted with the sign bit if one
|
|
// fewer byte were used, and so such encodings are minimal.
|
|
// An example of this is +-255, which have minimal encodings
|
|
// [0xff, 0x00] and [0xff, 0x80] respectively.
|
|
if vch.len() <= 1 || (vch[vch.len() - 2] & 0x80) == 0 {
|
|
return Err(ScriptNumError::NonMinimalEncoding);
|
|
}
|
|
}
|
|
}
|
|
Self::set_vch(vch).map(ScriptNum)
|
|
}
|
|
|
|
pub fn getint(&self) -> i32 {
|
|
if self.0 > i32::MAX.into() {
|
|
i32::MAX
|
|
} else if self.0 < i32::MIN.into() {
|
|
i32::MIN
|
|
} else {
|
|
self.0.try_into().unwrap()
|
|
}
|
|
}
|
|
|
|
pub fn getvch(&self) -> Vec<u8> {
|
|
Self::serialize(&self.0)
|
|
}
|
|
|
|
pub fn serialize(value: &i64) -> Vec<u8> {
|
|
if *value == 0 {
|
|
return Vec::new();
|
|
}
|
|
|
|
if *value == i64::MIN {
|
|
// The code below was based on buggy C++ code, that produced the
|
|
// "wrong" result for INT64_MIN. In that case we intentionally return
|
|
// the result that the C++ code as compiled for zcashd (with `-fwrapv`)
|
|
// originally produced on an x86_64 system.
|
|
return vec![0, 0, 0, 0, 0, 0, 0, 128, 128];
|
|
}
|
|
|
|
let mut result = Vec::new();
|
|
let neg = *value < 0;
|
|
let mut absvalue = value.unsigned_abs();
|
|
|
|
while absvalue != 0 {
|
|
result.push((absvalue & 0xff).try_into().expect("fits in u8"));
|
|
absvalue >>= 8;
|
|
}
|
|
|
|
// - If the most significant byte is >= 0x80 and the value is positive, push a
|
|
// new zero-byte to make the significant byte < 0x80 again.
|
|
// - If the most significant byte is >= 0x80 and the value is negative, push a
|
|
// new 0x80 byte that will be popped off when converting to an integral.
|
|
// - If the most significant byte is < 0x80 and the value is negative, add 0x80
|
|
// to it, since it will be subtracted and interpreted as a negative when
|
|
// converting to an integral.
|
|
|
|
let result_back = result.last_mut().expect("not empty");
|
|
if *result_back & 0x80 != 0 {
|
|
result.push(if neg { 0x80 } else { 0 });
|
|
} else if neg {
|
|
*result_back |= 0x80;
|
|
}
|
|
|
|
result
|
|
}
|
|
|
|
fn set_vch(vch: &Vec<u8>) -> Result<i64, ScriptNumError> {
|
|
match vch.last() {
|
|
None => Ok(0),
|
|
Some(vch_back) => {
|
|
if *vch == vec![0, 0, 0, 0, 0, 0, 0, 128, 128] {
|
|
// Match the behaviour of the C++ code, which special-cased this
|
|
// encoding to avoid an undefined shift of a signed type by 64 bits.
|
|
return Ok(i64::MIN);
|
|
};
|
|
|
|
// Ensure defined behaviour (in Rust, left shift of `i64` by 64 bits
|
|
// is an arithmetic overflow that may panic or give an unspecified
|
|
// result). The above encoding of `i64::MIN` is the only allowed
|
|
// 9-byte encoding.
|
|
if vch.len() > 8 {
|
|
return Err(ScriptNumError::Overflow {
|
|
max_num_size: 8,
|
|
actual: vch.len(),
|
|
});
|
|
};
|
|
|
|
let mut result: i64 = 0;
|
|
for (i, vch_i) in vch.iter().enumerate() {
|
|
result |= i64::from(*vch_i) << (8 * i);
|
|
}
|
|
|
|
// If the input vector's most significant byte is 0x80, remove it from
|
|
// the result's msb and return a negative.
|
|
if vch_back & 0x80 != 0 {
|
|
return Ok(-(result & !(0x80 << (8 * (vch.len() - 1)))));
|
|
};
|
|
|
|
Ok(result)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<i32> for ScriptNum {
|
|
fn from(value: i32) -> Self {
|
|
ScriptNum(value.into())
|
|
}
|
|
}
|
|
|
|
impl From<u32> for ScriptNum {
|
|
fn from(value: u32) -> Self {
|
|
ScriptNum(value.into())
|
|
}
|
|
}
|
|
|
|
impl From<u8> for ScriptNum {
|
|
fn from(value: u8) -> Self {
|
|
ScriptNum(value.into())
|
|
}
|
|
}
|
|
|
|
/// TODO: This instance will be obsolete if we convert bool directly to a `Vec<u8>`, which is also
|
|
/// more efficient.
|
|
impl From<bool> for ScriptNum {
|
|
fn from(value: bool) -> Self {
|
|
ScriptNum(value.into())
|
|
}
|
|
}
|
|
|
|
impl TryFrom<usize> for ScriptNum {
|
|
type Error = TryFromIntError;
|
|
fn try_from(value: usize) -> Result<Self, Self::Error> {
|
|
value.try_into().map(ScriptNum)
|
|
}
|
|
}
|
|
|
|
impl TryFrom<ScriptNum> for u16 {
|
|
type Error = TryFromIntError;
|
|
fn try_from(value: ScriptNum) -> Result<Self, Self::Error> {
|
|
value.getint().try_into()
|
|
}
|
|
}
|
|
|
|
impl TryFrom<ScriptNum> for u8 {
|
|
type Error = TryFromIntError;
|
|
fn try_from(value: ScriptNum) -> Result<Self, Self::Error> {
|
|
value.getint().try_into()
|
|
}
|
|
}
|
|
|
|
impl Add for ScriptNum {
|
|
type Output = Self;
|
|
|
|
fn add(self, other: Self) -> Self {
|
|
Self(
|
|
self.0
|
|
.checked_add(other.0)
|
|
.expect("caller should avoid overflow"),
|
|
)
|
|
}
|
|
}
|
|
|
|
impl Sub for ScriptNum {
|
|
type Output = Self;
|
|
|
|
fn sub(self, other: Self) -> Self {
|
|
Self(
|
|
self.0
|
|
.checked_sub(other.0)
|
|
.expect("caller should avoid underflow"),
|
|
)
|
|
}
|
|
}
|
|
|
|
impl Neg for ScriptNum {
|
|
type Output = Self;
|
|
|
|
fn neg(self) -> Self {
|
|
assert!(self.0 != i64::MIN);
|
|
Self(-self.0)
|
|
}
|
|
}
|
|
|
|
/** Serialized script, used inside transaction inputs and outputs */
|
|
#[derive(Clone, Debug)]
|
|
pub struct Script<'a>(pub &'a [u8]);
|
|
|
|
impl Script<'_> {
|
|
pub fn get_op(script: &[u8]) -> Result<(Opcode, &[u8]), ScriptError> {
|
|
Self::get_op2(script).map(|(op, _, remainder)| (op, remainder))
|
|
}
|
|
|
|
fn split_value(script: &[u8], needed_bytes: usize) -> Result<(&[u8], &[u8]), ScriptError> {
|
|
script
|
|
.split_at_checked(needed_bytes)
|
|
.ok_or(ScriptError::ReadError {
|
|
expected_bytes: needed_bytes,
|
|
available_bytes: script.len(),
|
|
})
|
|
}
|
|
|
|
/// First splits `size_size` bytes to determine the size of the value to read, then splits the
|
|
/// value.
|
|
fn split_tagged_value(script: &[u8], size_size: usize) -> Result<(&[u8], &[u8]), ScriptError> {
|
|
Script::split_value(script, size_size).and_then(|(bytes, script)| {
|
|
let mut size = 0;
|
|
for byte in bytes.iter().rev() {
|
|
size <<= 8;
|
|
size |= usize::from(*byte);
|
|
}
|
|
Script::split_value(script, size)
|
|
})
|
|
}
|
|
|
|
pub fn get_op2(script: &[u8]) -> Result<(Opcode, &[u8], &[u8]), ScriptError> {
|
|
match script.split_first() {
|
|
None => Err(ScriptError::ReadError {
|
|
expected_bytes: 1,
|
|
available_bytes: 0,
|
|
}),
|
|
Some((leading_byte, script)) => match Opcode::from(*leading_byte) {
|
|
op @ Opcode::PushValue(pv) => match pv {
|
|
OP_PUSHDATA1 => Script::split_tagged_value(script, 1),
|
|
OP_PUSHDATA2 => Script::split_tagged_value(script, 2),
|
|
OP_PUSHDATA4 => Script::split_tagged_value(script, 4),
|
|
PushdataBytelength(size_byte) => Script::split_value(script, size_byte.into()),
|
|
_ => Ok((&[][..], script)),
|
|
}
|
|
.map(|(value, script)| (op, value, script)),
|
|
op => Ok((op, &[], script)),
|
|
},
|
|
}
|
|
}
|
|
|
|
/** Encode/decode small integers: */
|
|
pub fn decode_op_n(opcode: PushValue) -> u32 {
|
|
if opcode == OP_0 {
|
|
return 0;
|
|
}
|
|
assert!(opcode >= OP_1 && opcode <= OP_16);
|
|
(u8::from(opcode) - (u8::from(OP_1) - 1)).into()
|
|
}
|
|
|
|
/// Pre-version-0.6, Bitcoin always counted CHECKMULTISIGs
|
|
/// as 20 sigops. With pay-to-script-hash, that changed:
|
|
/// CHECKMULTISIGs serialized in script_sigs are
|
|
/// counted more accurately, assuming they are of the form
|
|
/// ... OP_N CHECKMULTISIG ...
|
|
pub fn get_sig_op_count(&self, accurate: bool) -> u32 {
|
|
let mut n = 0;
|
|
let mut pc = self.0;
|
|
let mut last_opcode = Opcode::Operation(OP_INVALIDOPCODE);
|
|
while !pc.is_empty() {
|
|
let (opcode, new_pc) = match Self::get_op(pc) {
|
|
Ok(o) => o,
|
|
// Stop counting when we get to an invalid opcode.
|
|
Err(_) => break,
|
|
};
|
|
pc = new_pc;
|
|
if let Opcode::Operation(op) = opcode {
|
|
if op == OP_CHECKSIG || op == OP_CHECKSIGVERIFY {
|
|
n += 1;
|
|
} else if op == OP_CHECKMULTISIG || op == OP_CHECKMULTISIGVERIFY {
|
|
match last_opcode {
|
|
Opcode::PushValue(pv) => {
|
|
if accurate && pv >= OP_1 && pv <= OP_16 {
|
|
n += Self::decode_op_n(pv);
|
|
} else {
|
|
n += 20
|
|
}
|
|
}
|
|
_ => n += 20,
|
|
}
|
|
}
|
|
}
|
|
last_opcode = opcode;
|
|
}
|
|
n
|
|
}
|
|
|
|
/// Returns true iff this script is P2SH.
|
|
pub fn is_pay_to_script_hash(&self) -> bool {
|
|
self.0.len() == 23
|
|
&& self.0[0] == OP_HASH160.into()
|
|
&& self.0[1] == 0x14
|
|
&& self.0[22] == OP_EQUAL.into()
|
|
}
|
|
|
|
/// Called by `IsStandardTx` and P2SH/BIP62 VerifyScript (which makes it consensus-critical).
|
|
pub fn is_push_only(&self) -> bool {
|
|
let mut pc = self.0;
|
|
while !pc.is_empty() {
|
|
if let Ok((Opcode::PushValue(_), new_pc)) = Self::get_op(pc) {
|
|
pc = new_pc;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
true
|
|
}
|
|
}
|