script pretty printing
This commit is contained in:
parent
585ea7a0c7
commit
2ac5ee73d3
|
@ -3,7 +3,7 @@ use keys::{Public, Signature};
|
|||
use hash::{H256, h256_from_u8};
|
||||
use transaction::{Transaction, SEQUENCE_LOCKTIME_DISABLE_FLAG};
|
||||
use crypto::{sha1, sha256, dhash160, dhash256, ripemd160};
|
||||
use script::{script, Script, Num, VerificationFlags, Opcode, Error};
|
||||
use script::{script, Script, Num, VerificationFlags, Opcode, Error, read_usize};
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
#[repr(u8)]
|
||||
|
@ -336,19 +336,6 @@ fn require_len(stack: &Vec<Vec<u8>>, len: usize) -> Result<(), Error> {
|
|||
}
|
||||
}
|
||||
|
||||
fn read_usize(data: &[u8], size: usize) -> Result<usize, Error> {
|
||||
if data.len() < size {
|
||||
return Err(Error::BadOpcode);
|
||||
}
|
||||
|
||||
let result = data
|
||||
.iter()
|
||||
.take(size)
|
||||
.enumerate()
|
||||
.fold(0, |acc, (i, x)| acc + ((*x as usize) << (i * 8)));
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn eval_script(
|
||||
stack: &mut Vec<Vec<u8>>,
|
||||
script: &Script,
|
||||
|
|
|
@ -14,7 +14,7 @@ pub use self::flags::VerificationFlags;
|
|||
pub use self::interpreter::eval_script;
|
||||
pub use self::opcode::Opcode;
|
||||
pub use self::num::Num;
|
||||
pub use self::script::{Script, ScriptWitness};
|
||||
pub use self::script::{Script, ScriptWitness, read_usize};
|
||||
pub use self::sign::SignatureData;
|
||||
pub use self::standard::TransactionType;
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
//! Script opcodes.
|
||||
use std::fmt;
|
||||
|
||||
/// Script opcodes.
|
||||
#[repr(u8)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
|
||||
pub enum Opcode {
|
||||
// push value
|
||||
OP_0 = 0x00,
|
||||
|
@ -219,6 +222,12 @@ pub enum Opcode {
|
|||
OP_INVALIDOPCODE = 0xff,
|
||||
}
|
||||
|
||||
impl fmt::Display for Opcode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Debug::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Opcode {
|
||||
pub fn from_u8(u: u8) -> Option<Self> {
|
||||
use self::Opcode::*;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
//! Serialized script, used inside transaction inputs and outputs.
|
||||
|
||||
use std::fmt;
|
||||
use hex::ToHex;
|
||||
use script::{Opcode, Error, Num};
|
||||
|
||||
/// Maximum number of bytes pushable to the stack
|
||||
|
@ -104,6 +106,71 @@ impl Script {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn read_usize(data: &[u8], size: usize) -> Result<usize, Error> {
|
||||
if data.len() < size {
|
||||
return Err(Error::BadOpcode);
|
||||
}
|
||||
|
||||
let result = data
|
||||
.iter()
|
||||
.take(size)
|
||||
.enumerate()
|
||||
.fold(0, |acc, (i, x)| acc + ((*x as usize) << (i * 8)));
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
macro_rules! try_or_fmt {
|
||||
($fmt: expr, $expr: expr) => {
|
||||
match $expr {
|
||||
Ok(o) => o,
|
||||
Err(e) => return e.fmt($fmt),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Script {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str(&self.data.to_hex())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Script {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut pc = 0;
|
||||
while pc < self.len() {
|
||||
let opcode = try_or_fmt!(f, self.get_opcode(pc));
|
||||
|
||||
match opcode {
|
||||
Opcode::OP_PUSHDATA1 |
|
||||
Opcode::OP_PUSHDATA2 |
|
||||
Opcode::OP_PUSHDATA4 => {
|
||||
let len = match opcode {
|
||||
Opcode::OP_PUSHDATA1 => 1,
|
||||
Opcode::OP_PUSHDATA2 => 2,
|
||||
_ => 4,
|
||||
};
|
||||
|
||||
let slice = try_or_fmt!(f, self.take(pc + 1, len));
|
||||
let n = try_or_fmt!(f, read_usize(slice, len));
|
||||
let bytes = try_or_fmt!(f, self.take_checked(pc + 1 + len, n));
|
||||
pc += len + n;
|
||||
try!(writeln!(f, "{:?} 0x{}", opcode, bytes.to_hex()));
|
||||
},
|
||||
o if o >= Opcode::OP_0 && o <= Opcode::OP_PUSHBYTES_75 => {
|
||||
let bytes = try_or_fmt!(f, self.take_checked(pc + 1, opcode as usize));
|
||||
pc += opcode as usize;
|
||||
try!(writeln!(f, "{:?} 0x{}", opcode, bytes.to_hex()));
|
||||
},
|
||||
_ => {
|
||||
try!(writeln!(f, "{:?}", opcode));
|
||||
},
|
||||
}
|
||||
pc += 1;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ScriptWitness {
|
||||
script: Vec<Vec<u8>>,
|
||||
}
|
||||
|
@ -111,6 +178,7 @@ pub struct ScriptWitness {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use hex::FromHex;
|
||||
use script::{Builder, Opcode};
|
||||
use super::Script;
|
||||
|
||||
#[test]
|
||||
|
@ -128,4 +196,33 @@ mod tests {
|
|||
assert!(Script::new(data).is_pay_to_witness_script_hash());
|
||||
assert!(!Script::new(data2).is_pay_to_witness_script_hash());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_script_debug() {
|
||||
use std::fmt::Write;
|
||||
|
||||
let script = Builder::default()
|
||||
.push_num(3.into())
|
||||
.push_num(2.into())
|
||||
.push_opcode(Opcode::OP_ADD)
|
||||
.into_script();
|
||||
let s = "0103010293";
|
||||
let mut res = String::new();
|
||||
write!(&mut res, "{:?}", script).unwrap();
|
||||
assert_eq!(s.to_string(), res);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_script_display() {
|
||||
let script = Builder::default()
|
||||
.push_num(3.into())
|
||||
.push_num(2.into())
|
||||
.push_opcode(Opcode::OP_ADD)
|
||||
.into_script();
|
||||
let s = r#"OP_PUSHBYTES_1 0x03
|
||||
OP_PUSHBYTES_1 0x02
|
||||
OP_ADD
|
||||
"#;
|
||||
assert_eq!(script.to_string(), s.to_string());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ impl Deserializable for OutPoint {
|
|||
#[derive(Debug)]
|
||||
pub struct TransactionInput {
|
||||
previous_output: OutPoint,
|
||||
signature_script: Vec<u8>,
|
||||
script_sig: Vec<u8>,
|
||||
sequence: u32,
|
||||
}
|
||||
|
||||
|
@ -52,8 +52,8 @@ impl Serializable for TransactionInput {
|
|||
fn serialize(&self, stream: &mut Stream) {
|
||||
stream
|
||||
.append(&self.previous_output)
|
||||
.append(&CompactInteger::from(self.signature_script.len()))
|
||||
.append_bytes(&self.signature_script)
|
||||
.append(&CompactInteger::from(self.script_sig.len()))
|
||||
.append_bytes(&self.script_sig)
|
||||
.append(&self.sequence);
|
||||
}
|
||||
}
|
||||
|
@ -61,13 +61,13 @@ impl Serializable for TransactionInput {
|
|||
impl Deserializable for TransactionInput {
|
||||
fn deserialize(reader: &mut Reader) -> Result<Self, ReaderError> where Self: Sized {
|
||||
let previous_output = try!(reader.read());
|
||||
let signature_script_len = try!(reader.read::<CompactInteger>());
|
||||
let signature_script = try!(reader.read_bytes(signature_script_len.into())).to_vec();
|
||||
let script_sig_len = try!(reader.read::<CompactInteger>());
|
||||
let script_sig = try!(reader.read_bytes(script_sig_len.into())).to_vec();
|
||||
let sequence = try!(reader.read());
|
||||
|
||||
let result = TransactionInput {
|
||||
previous_output: previous_output,
|
||||
signature_script: signature_script,
|
||||
script_sig: script_sig,
|
||||
sequence: sequence,
|
||||
};
|
||||
|
||||
|
@ -78,27 +78,27 @@ impl Deserializable for TransactionInput {
|
|||
#[derive(Debug)]
|
||||
pub struct TransactionOutput {
|
||||
value: u64,
|
||||
pk_script: Vec<u8>,
|
||||
script_pubkey: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Serializable for TransactionOutput {
|
||||
fn serialize(&self, stream: &mut Stream) {
|
||||
stream
|
||||
.append(&self.value)
|
||||
.append(&CompactInteger::from(self.pk_script.len()))
|
||||
.append_bytes(&self.pk_script);
|
||||
.append(&CompactInteger::from(self.script_pubkey.len()))
|
||||
.append_bytes(&self.script_pubkey);
|
||||
}
|
||||
}
|
||||
|
||||
impl Deserializable for TransactionOutput {
|
||||
fn deserialize(reader: &mut Reader) -> Result<Self, ReaderError> where Self: Sized {
|
||||
let value = try!(reader.read());
|
||||
let pk_script_len = try!(reader.read::<CompactInteger>());
|
||||
let pk_script = try!(reader.read_bytes(pk_script_len.into())).to_vec();
|
||||
let script_pubkey_len = try!(reader.read::<CompactInteger>());
|
||||
let script_pubkey = try!(reader.read_bytes(script_pubkey_len.into())).to_vec();
|
||||
|
||||
let result = TransactionOutput {
|
||||
value: value,
|
||||
pk_script: pk_script,
|
||||
script_pubkey: script_pubkey,
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
|
@ -179,10 +179,10 @@ mod tests {
|
|||
assert_eq!(t.transaction_outputs.len(), 1);
|
||||
let tx_input = &t.transaction_inputs[0];
|
||||
assert_eq!(tx_input.sequence, 4294967295);
|
||||
assert_eq!(tx_input.signature_script, "48304502206e21798a42fae0e854281abd38bacd1aeed3ee3738d9e1446618c4571d1090db022100e2ac980643b0b82c0e88ffdfec6b64e3e6ba35e7ba5fdd7d5d6cc8d25c6b241501".from_hex().unwrap());
|
||||
assert_eq!(tx_input.script_sig, "48304502206e21798a42fae0e854281abd38bacd1aeed3ee3738d9e1446618c4571d1090db022100e2ac980643b0b82c0e88ffdfec6b64e3e6ba35e7ba5fdd7d5d6cc8d25c6b241501".from_hex().unwrap());
|
||||
let tx_output = &t.transaction_outputs[0];
|
||||
assert_eq!(tx_output.value, 5000000000);
|
||||
assert_eq!(tx_output.pk_script, "76a914404371705fa9bd789a2fcd52d2c580b65d35549d88ac".from_hex().unwrap());
|
||||
assert_eq!(tx_output.script_pubkey, "76a914404371705fa9bd789a2fcd52d2c580b65d35549d88ac".from_hex().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Reference in New Issue