parity-zcash/src/script/script.rs

132 lines
3.3 KiB
Rust
Raw Normal View History

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());
}
}