2016-08-19 05:50:22 -07:00
|
|
|
//! Serialized script, used inside transaction inputs and outputs.
|
|
|
|
|
2016-08-23 06:07:14 -07:00
|
|
|
use script::{Opcode, Error, Num};
|
2016-08-19 05:50:22 -07:00
|
|
|
|
|
|
|
/// Maximum number of bytes pushable to the stack
|
2016-08-23 06:07:14 -07:00
|
|
|
const MAX_SCRIPT_ELEMENT_SIZE: usize = 520;
|
2016-08-19 05:50:22 -07:00
|
|
|
|
|
|
|
/// Maximum number of non-push operations per script
|
2016-08-20 09:25:41 -07:00
|
|
|
const _MAX_OPS_PER_SCRIPT: u32 = 201;
|
2016-08-19 05:50:22 -07:00
|
|
|
|
|
|
|
/// Maximum number of public keys per multisig
|
2016-08-20 09:25:41 -07:00
|
|
|
const _MAX_PUBKEYS_PER_MULTISIG: u32 = 20;
|
2016-08-19 05:50:22 -07:00
|
|
|
|
|
|
|
/// Maximum script length in bytes
|
2016-08-23 06:07:14 -07:00
|
|
|
pub const MAX_SCRIPT_SIZE: usize = 10000;
|
2016-08-19 05:50:22 -07:00
|
|
|
|
|
|
|
/// Threshold for nLockTime: below this value it is interpreted as block number,
|
|
|
|
/// otherwise as UNIX timestamp.
|
2016-08-20 09:25:41 -07:00
|
|
|
const _LOCKTIME_THRESHOLD: u32 = 500000000; // Tue Nov 5 00:53:20 1985 UTC
|
2016-08-19 05:50:22 -07:00
|
|
|
|
|
|
|
/// Serialized script, used inside transaction inputs and outputs.
|
|
|
|
pub struct Script {
|
|
|
|
data: Vec<u8>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Script {
|
|
|
|
/// Script constructor.
|
|
|
|
pub fn new(data: Vec<u8>) -> Self {
|
|
|
|
Script {
|
|
|
|
data: data,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Extra-fast test for pay-to-script-hash scripts.
|
|
|
|
pub fn is_pay_to_script_hash(&self) -> bool {
|
|
|
|
self.data.len() == 23 &&
|
|
|
|
self.data[0] == Opcode::OP_HASH160 as u8 &&
|
|
|
|
self.data[1] == 0x14 &&
|
|
|
|
self.data[22] == Opcode::OP_EQUAL as u8
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Extra-fast test for pay-to-witness-script-hash scripts.
|
|
|
|
pub fn is_pay_to_witness_script_hash(&self) -> bool {
|
|
|
|
self.data.len() == 34 &&
|
|
|
|
self.data[0] == Opcode::OP_0 as u8 &&
|
|
|
|
self.data[1] == 0x20
|
|
|
|
}
|
2016-08-23 06:07:14 -07:00
|
|
|
|
|
|
|
pub fn is_empty(&self) -> bool {
|
|
|
|
self.data.is_empty()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn len(&self) -> usize {
|
|
|
|
self.data.len()
|
|
|
|
}
|
|
|
|
|
2016-09-11 03:22:25 -07:00
|
|
|
pub fn subscript(&self, from: usize) -> Script {
|
|
|
|
Script::new(self.data[from..].to_vec())
|
|
|
|
}
|
2016-08-23 06:07:14 -07:00
|
|
|
|
2016-09-11 03:22:25 -07:00
|
|
|
pub fn find_and_delete(&self, data: &[u8]) -> Script {
|
|
|
|
let mut result = Vec::new();
|
|
|
|
let mut current = 0;
|
|
|
|
let len = data.len();
|
|
|
|
let end = self.data.len();
|
2016-08-23 06:07:14 -07:00
|
|
|
|
2016-09-11 03:22:25 -07:00
|
|
|
if len > end {
|
|
|
|
return Script::new(data.to_vec());
|
|
|
|
}
|
2016-08-23 06:07:14 -07:00
|
|
|
|
2016-09-11 03:22:25 -07:00
|
|
|
while current < end - len {
|
|
|
|
if &self.data[current..len] != data {
|
|
|
|
result.push(self.data[current]);
|
|
|
|
current += 1;
|
|
|
|
} else {
|
|
|
|
current += len;
|
|
|
|
}
|
2016-08-23 06:07:14 -07:00
|
|
|
}
|
|
|
|
|
2016-09-11 03:22:25 -07:00
|
|
|
result.extend_from_slice(&self.data[current..]);
|
|
|
|
Script::new(result)
|
2016-08-23 06:07:14 -07:00
|
|
|
}
|
|
|
|
|
2016-09-11 03:22:25 -07:00
|
|
|
pub fn get_opcode(&self, position: usize) -> Result<Opcode, Error> {
|
|
|
|
Opcode::from_u8(self.data[position]).ok_or(Error::BadOpcode)
|
|
|
|
}
|
2016-08-23 06:07:14 -07:00
|
|
|
|
|
|
|
#[inline]
|
2016-09-11 03:22:25 -07:00
|
|
|
pub fn take(&self, offset: usize, len: usize) -> Result<&[u8], Error> {
|
2016-08-23 06:07:14 -07:00
|
|
|
if offset + len > self.data.len() {
|
|
|
|
Err(Error::BadOpcode)
|
|
|
|
} else {
|
|
|
|
Ok(&self.data[offset..offset + len])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2016-09-11 03:22:25 -07:00
|
|
|
pub fn take_checked(&self, offset: usize, len: usize) -> Result<&[u8], Error> {
|
2016-08-23 06:07:14 -07:00
|
|
|
if len > MAX_SCRIPT_ELEMENT_SIZE {
|
|
|
|
Err(Error::ScriptSize)
|
|
|
|
} else {
|
|
|
|
self.take(offset, len)
|
|
|
|
}
|
|
|
|
}
|
2016-08-19 05:50:22 -07:00
|
|
|
}
|
|
|
|
|
2016-09-07 07:15:07 -07:00
|
|
|
pub struct ScriptWitness {
|
|
|
|
script: Vec<Vec<u8>>,
|
|
|
|
}
|
|
|
|
|
2016-08-19 05:50:22 -07:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use hex::FromHex;
|
|
|
|
use super::Script;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_is_pay_to_script_hash() {
|
|
|
|
let data = "a9143b80842f4ea32806ce5e723a255ddd6490cfd28d87".from_hex().unwrap();
|
|
|
|
let data2 = "a9143b80842f4ea32806ce5e723a255ddd6490cfd28d88".from_hex().unwrap();
|
|
|
|
assert!(Script::new(data).is_pay_to_script_hash());
|
|
|
|
assert!(!Script::new(data2).is_pay_to_script_hash());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_is_pay_to_witness_script_hash() {
|
|
|
|
let data = "00203b80842f4ea32806ce5e723a255ddd6490cfd28dac38c58bf9254c0577330693".from_hex().unwrap();
|
|
|
|
let data2 = "01203b80842f4ea32806ce5e723a255ddd6490cfd28dac38c58bf9254c0577330693".from_hex().unwrap();
|
|
|
|
assert!(Script::new(data).is_pay_to_witness_script_hash());
|
|
|
|
assert!(!Script::new(data2).is_pay_to_witness_script_hash());
|
|
|
|
}
|
|
|
|
}
|