Implement script except for crypto opcodes, replace zero_hash by Default
Looks like to implement the crypto opcodes I may need to switch from rust-crypto to rust-openssl.. or implement RIPEMD-160 for rust-crypto. In either case I will need to generalize the hash.rs stuff to support other hashes, so I'm committing here as a checkpoint before doing all that.
This commit is contained in:
parent
2986e1f983
commit
ecdb750148
|
@ -158,9 +158,9 @@ mod tests {
|
|||
assert!(bad_decode.is_err());
|
||||
let real_decode = decode.unwrap();
|
||||
assert_eq!(real_decode.header.version, 1);
|
||||
assert_eq!(real_decode.header.prev_blockhash.as_slice(), prevhash.as_slice());
|
||||
assert_eq!(serialize(&real_decode.header.prev_blockhash), Ok(prevhash));
|
||||
// [test] TODO: actually compute the merkle root
|
||||
assert_eq!(real_decode.header.merkle_root.as_slice(), merkle.as_slice());
|
||||
assert_eq!(serialize(&real_decode.header.merkle_root), Ok(merkle));
|
||||
assert_eq!(real_decode.header.time, 1231965655);
|
||||
assert_eq!(real_decode.header.bits, 486604799);
|
||||
assert_eq!(real_decode.header.nonce, 2067413810);
|
||||
|
|
|
@ -19,16 +19,16 @@
|
|||
//! single transaction
|
||||
//!
|
||||
|
||||
use network::constants::{Network, Bitcoin, BitcoinTestnet};
|
||||
|
||||
use std::default::Default;
|
||||
use std::num::from_u64;
|
||||
|
||||
use blockdata::opcodes;
|
||||
use blockdata::script::Script;
|
||||
use blockdata::transaction::{Transaction, TxOut, TxIn};
|
||||
use blockdata::block::{Block, BlockHeader};
|
||||
use network::constants::{Network, Bitcoin, BitcoinTestnet};
|
||||
use util::misc::hex_bytes;
|
||||
use util::hash::{MerkleRoot, zero_hash};
|
||||
use util::hash::MerkleRoot;
|
||||
use util::uint::Uint256;
|
||||
|
||||
pub static MAX_SEQUENCE: u32 = 0xFFFFFFFF;
|
||||
|
@ -58,7 +58,7 @@ fn bitcoin_genesis_tx() -> Transaction {
|
|||
in_script.push_scriptint(4);
|
||||
in_script.push_slice("The Times 03/Jan/2009 Chancellor on brink of second bailout for banks".as_bytes());
|
||||
ret.input.push(TxIn {
|
||||
prev_hash: zero_hash(),
|
||||
prev_hash: Default::default(),
|
||||
prev_index: 0xFFFFFFFF,
|
||||
script_sig: in_script,
|
||||
sequence: MAX_SEQUENCE
|
||||
|
@ -67,7 +67,7 @@ fn bitcoin_genesis_tx() -> Transaction {
|
|||
// Outputs
|
||||
let mut out_script = Script::new();
|
||||
out_script.push_slice(hex_bytes("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f").unwrap().as_slice());
|
||||
out_script.push_opcode(opcodes::CHECKSIG);
|
||||
out_script.push_opcode(opcodes::OP_CHECKSIG);
|
||||
ret.output.push(TxOut {
|
||||
value: 50 * COIN_VALUE,
|
||||
script_pubkey: out_script
|
||||
|
@ -85,7 +85,7 @@ pub fn genesis_block(network: Network) -> Block {
|
|||
Block {
|
||||
header: BlockHeader {
|
||||
version: 1,
|
||||
prev_blockhash: zero_hash(),
|
||||
prev_blockhash: Default::default(),
|
||||
merkle_root: txdata.merkle_root(),
|
||||
time: 1231006505,
|
||||
bits: 0x1d00ffff,
|
||||
|
@ -99,7 +99,7 @@ pub fn genesis_block(network: Network) -> Block {
|
|||
Block {
|
||||
header: BlockHeader {
|
||||
version: 1,
|
||||
prev_blockhash: zero_hash(),
|
||||
prev_blockhash: Default::default(),
|
||||
merkle_root: txdata.merkle_root(),
|
||||
time: 1296688602,
|
||||
bits: 0x1d00ffff,
|
||||
|
@ -113,13 +113,13 @@ pub fn genesis_block(network: Network) -> Block {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::default::Default;
|
||||
use serialize::hex::FromHex;
|
||||
|
||||
use network::constants::{Bitcoin, BitcoinTestnet};
|
||||
use network::serialize::{BitcoinHash, serialize};
|
||||
use blockdata::constants::{genesis_block, bitcoin_genesis_tx};
|
||||
use blockdata::constants::{MAX_SEQUENCE, COIN_VALUE};
|
||||
use util::hash::zero_hash;
|
||||
|
||||
#[test]
|
||||
fn bitcoin_genesis_first_transaction() {
|
||||
|
@ -127,7 +127,7 @@ mod test {
|
|||
|
||||
assert_eq!(gen.version, 1);
|
||||
assert_eq!(gen.input.len(), 1);
|
||||
assert_eq!(gen.input[0].prev_hash.as_slice(), zero_hash().as_slice());
|
||||
assert_eq!(gen.input[0].prev_hash, Default::default());
|
||||
assert_eq!(gen.input[0].prev_index, 0xFFFFFFFF);
|
||||
assert_eq!(serialize(&gen.input[0].script_sig),
|
||||
Ok("4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73".from_hex().unwrap()));
|
||||
|
@ -148,7 +148,7 @@ mod test {
|
|||
let gen = genesis_block(Bitcoin);
|
||||
|
||||
assert_eq!(gen.header.version, 1);
|
||||
assert_eq!(gen.header.prev_blockhash.as_slice(), zero_hash().as_slice());
|
||||
assert_eq!(gen.header.prev_blockhash, Default::default());
|
||||
assert_eq!(gen.header.merkle_root.be_hex_string(),
|
||||
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".to_string());
|
||||
assert_eq!(gen.header.time, 1231006505);
|
||||
|
@ -162,7 +162,7 @@ mod test {
|
|||
fn testnet_genesis_full_block() {
|
||||
let gen = genesis_block(BitcoinTestnet);
|
||||
assert_eq!(gen.header.version, 1);
|
||||
assert_eq!(gen.header.prev_blockhash.as_slice(), zero_hash().as_slice());
|
||||
assert_eq!(gen.header.prev_blockhash, Default::default());
|
||||
assert_eq!(gen.header.merkle_root.be_hex_string(),
|
||||
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".to_string());
|
||||
assert_eq!(gen.header.time, 1296688602);
|
||||
|
|
|
@ -15,14 +15,667 @@
|
|||
//! # Opcodes
|
||||
//!
|
||||
//! Bitcoin's script uses a stack-based assembly language. This module defines
|
||||
//! the mapping from assembler instructions to bytes.
|
||||
//! all of the opcodes
|
||||
//!
|
||||
|
||||
pub static FALSE: u8 = 0x00;
|
||||
pub static TRUE: u8 = 0x51;
|
||||
pub static PUSHDATA1: u8 = 0x4C;
|
||||
pub static PUSHDATA2: u8 = 0x4D;
|
||||
pub static PUSHDATA4: u8 = 0x4E;
|
||||
pub static CHECKSIG: u8 = 0xAC;
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
|
||||
/// Submodule to handle -all- opcodes. Outside of this module we use
|
||||
/// a restricted set where the push/return/noop/illegal opcodes have
|
||||
/// a more convienient representation.
|
||||
pub mod all {
|
||||
// Heavy stick to translate between opcode types
|
||||
use std::mem::transmute;
|
||||
|
||||
use network::serialize::{SimpleDecoder, SimpleEncoder};
|
||||
use network::encodable::{ConsensusDecodable, ConsensusEncodable};
|
||||
|
||||
// Note: I am deliberately not implementing PartialOrd or Ord on the
|
||||
// opcode enum. If you want to check ranges of opcodes, etc.,
|
||||
// write an #[inline] helper function which casts to u8s.
|
||||
|
||||
/// A script Opcode
|
||||
#[deriving(Clone, PartialEq, Eq, Show)]
|
||||
#[repr(u8)]
|
||||
pub enum Opcode {
|
||||
/// Push an empty array onto the stack
|
||||
OP_PUSHBYTES_0 = 0x0,
|
||||
/// Push the next byte as an array onto the stack
|
||||
OP_PUSHBYTES_1 = 0x01,
|
||||
/// Push the next 2 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_2 = 0x02,
|
||||
/// Push the next 2 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_3 = 0x03,
|
||||
/// Push the next 4 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_4 = 0x04,
|
||||
/// Push the next 5 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_5 = 0x05,
|
||||
/// Push the next 6 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_6 = 0x06,
|
||||
/// Push the next 7 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_7 = 0x07,
|
||||
/// Push the next 8 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_8 = 0x08,
|
||||
/// Push the next 9 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_9 = 0x09,
|
||||
/// Push the next 10 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_10 = 0x0a,
|
||||
/// Push the next 11 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_11 = 0x0b,
|
||||
/// Push the next 12 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_12 = 0x0c,
|
||||
/// Push the next 13 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_13 = 0x0d,
|
||||
/// Push the next 14 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_14 = 0x0e,
|
||||
/// Push the next 15 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_15 = 0x0f,
|
||||
/// Push the next 16 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_16 = 0x10,
|
||||
/// Push the next 17 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_17 = 0x11,
|
||||
/// Push the next 18 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_18 = 0x12,
|
||||
/// Push the next 19 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_19 = 0x13,
|
||||
/// Push the next 20 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_20 = 0x14,
|
||||
/// Push the next 21 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_21 = 0x15,
|
||||
/// Push the next 22 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_22 = 0x16,
|
||||
/// Push the next 23 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_23 = 0x17,
|
||||
/// Push the next 24 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_24 = 0x18,
|
||||
/// Push the next 25 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_25 = 0x19,
|
||||
/// Push the next 26 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_26 = 0x1a,
|
||||
/// Push the next 27 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_27 = 0x1b,
|
||||
/// Push the next 28 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_28 = 0x1c,
|
||||
/// Push the next 29 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_29 = 0x1d,
|
||||
/// Push the next 30 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_30 = 0x1e,
|
||||
/// Push the next 31 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_31 = 0x1f,
|
||||
/// Push the next 32 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_32 = 0x20,
|
||||
/// Push the next 33 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_33 = 0x21,
|
||||
/// Push the next 34 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_34 = 0x22,
|
||||
/// Push the next 35 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_35 = 0x23,
|
||||
/// Push the next 36 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_36 = 0x24,
|
||||
/// Push the next 37 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_37 = 0x25,
|
||||
/// Push the next 38 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_38 = 0x26,
|
||||
/// Push the next 39 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_39 = 0x27,
|
||||
/// Push the next 40 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_40 = 0x28,
|
||||
/// Push the next 41 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_41 = 0x29,
|
||||
/// Push the next 42 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_42 = 0x2a,
|
||||
/// Push the next 43 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_43 = 0x2b,
|
||||
/// Push the next 44 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_44 = 0x2c,
|
||||
/// Push the next 45 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_45 = 0x2d,
|
||||
/// Push the next 46 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_46 = 0x2e,
|
||||
/// Push the next 47 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_47 = 0x2f,
|
||||
/// Push the next 48 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_48 = 0x30,
|
||||
/// Push the next 49 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_49 = 0x31,
|
||||
/// Push the next 50 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_50 = 0x32,
|
||||
/// Push the next 51 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_51 = 0x33,
|
||||
/// Push the next 52 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_52 = 0x34,
|
||||
/// Push the next 53 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_53 = 0x35,
|
||||
/// Push the next 54 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_54 = 0x36,
|
||||
/// Push the next 55 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_55 = 0x37,
|
||||
/// Push the next 56 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_56 = 0x38,
|
||||
/// Push the next 57 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_57 = 0x39,
|
||||
/// Push the next 58 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_58 = 0x3a,
|
||||
/// Push the next 59 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_59 = 0x3b,
|
||||
/// Push the next 60 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_60 = 0x3c,
|
||||
/// Push the next 61 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_61 = 0x3d,
|
||||
/// Push the next 62 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_62 = 0x3e,
|
||||
/// Push the next 63 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_63 = 0x3f,
|
||||
/// Push the next 64 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_64 = 0x40,
|
||||
/// Push the next 65 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_65 = 0x41,
|
||||
/// Push the next 66 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_66 = 0x42,
|
||||
/// Push the next 67 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_67 = 0x43,
|
||||
/// Push the next 68 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_68 = 0x44,
|
||||
/// Push the next 69 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_69 = 0x45,
|
||||
/// Push the next 70 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_70 = 0x46,
|
||||
/// Push the next 71 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_71 = 0x47,
|
||||
/// Push the next 72 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_72 = 0x48,
|
||||
/// Push the next 73 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_73 = 0x49,
|
||||
/// Push the next 74 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_74 = 0x4a,
|
||||
/// Push the next 75 bytes as an array onto the stack
|
||||
OP_PUSHBYTES_75 = 0x4b,
|
||||
/// Read the next byte as N; push the next N bytes as an array onto the stack
|
||||
OP_PUSHDATA1 = 0x4c,
|
||||
/// Read the next 2 bytes as N; push the next N bytes as an array onto the stack
|
||||
OP_PUSHDATA2 = 0x4d,
|
||||
/// Read the next 4 bytes as N; push the next N bytes as an array onto the stack
|
||||
OP_PUSHDATA4 = 0x4e,
|
||||
/// Push the array [0x80] onto the stack
|
||||
OP_PUSHNUM_NEG1 = 0x4f,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RESERVED = 0x50,
|
||||
/// Push the array [0x01] onto the stack
|
||||
OP_PUSHNUM_1 = 0x51,
|
||||
/// Push the array [0x01] onto the stack
|
||||
OP_PUSHNUM_2 = 0x52,
|
||||
/// Push the array [0x01] onto the stack
|
||||
OP_PUSHNUM_3 = 0x53,
|
||||
/// Push the array [0x01] onto the stack
|
||||
OP_PUSHNUM_4 = 0x54,
|
||||
/// Push the array [0x01] onto the stack
|
||||
OP_PUSHNUM_5 = 0x55,
|
||||
/// Push the array [0x01] onto the stack
|
||||
OP_PUSHNUM_6 = 0x56,
|
||||
/// Push the array [0x01] onto the stack
|
||||
OP_PUSHNUM_7 = 0x57,
|
||||
/// Push the array [0x01] onto the stack
|
||||
OP_PUSHNUM_8 = 0x58,
|
||||
/// Push the array [0x01] onto the stack
|
||||
OP_PUSHNUM_9 = 0x59,
|
||||
/// Push the array [0x01] onto the stack
|
||||
OP_PUSHNUM_10 = 0x5a,
|
||||
/// Push the array [0x01] onto the stack
|
||||
OP_PUSHNUM_11 = 0x5b,
|
||||
/// Push the array [0x01] onto the stack
|
||||
OP_PUSHNUM_12 = 0x5c,
|
||||
/// Push the array [0x01] onto the stack
|
||||
OP_PUSHNUM_13 = 0x5d,
|
||||
/// Push the array [0x01] onto the stack
|
||||
OP_PUSHNUM_14 = 0x5e,
|
||||
/// Push the array [0x01] onto the stack
|
||||
OP_PUSHNUM_15 = 0x5f,
|
||||
/// Push the array [0x01] onto the stack
|
||||
OP_PUSHNUM_16 = 0x60,
|
||||
/// Does nothing
|
||||
OP_NOP = 0x61,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_VER = 0x62,
|
||||
/// Pop and execute the next statements if a nonzero element was popped
|
||||
OP_IF = 0x63,
|
||||
/// Pop and execute the next statements if a zero element was popped
|
||||
OP_NOTIF = 0x64,
|
||||
/// Fail the script unconditionally, does not even need to be executed
|
||||
OP_VERIF = 0x65,
|
||||
/// Fail the script unconditionally, does not even need to be executed
|
||||
OP_VERNOTIF = 0x66,
|
||||
/// Execute statements if those after the previous OP_IF were not, and vice-versa.
|
||||
/// If there is no previous OP_IF, this acts as a RETURN.
|
||||
OP_ELSE = 0x67,
|
||||
/// Pop and execute the next statements if a zero element was popped
|
||||
OP_ENDIF = 0x68,
|
||||
/// If the top value is zero or the stack is empty, fail; otherwise, pop the stack
|
||||
OP_VERIFY = 0x69,
|
||||
/// Fail the script immediately. (Must be executed.)
|
||||
OP_RETURN = 0x6a,
|
||||
/// Pop one element from the main stack onto the alt stack
|
||||
OP_TOALTSTACK = 0x6b,
|
||||
/// Pop one element from the alt stack onto the main stack
|
||||
OP_FROMALTSTACK = 0x6c,
|
||||
/// Drops the top two stack items
|
||||
OP_2DROP = 0x6d,
|
||||
/// Duplicates the top two stack items as AB -> ABAB
|
||||
OP_2DUP = 0x6e,
|
||||
/// Duplicates the two three stack items as ABC -> ABCABC
|
||||
OP_3DUP = 0x6f,
|
||||
/// Copies the two stack items of items two spaces back to
|
||||
/// the front, as xxAB -> ABxxAB
|
||||
OP_2OVER = 0x70,
|
||||
/// Moves the two stack items four spaces back to the front,
|
||||
/// as xxxxAB -> ABxxxx
|
||||
OP_2ROT = 0x71,
|
||||
/// Swaps the top two pairs, as ABCD -> CDAB
|
||||
OP_2SWAP = 0x72,
|
||||
/// Duplicate the top stack element unless it is zero
|
||||
OP_IFDUP = 0x73,
|
||||
/// Push the current number of stack items onto te stack
|
||||
OP_DEPTH = 0x74,
|
||||
/// Drops the top stack item
|
||||
OP_DROP = 0x75,
|
||||
/// Duplicates the top stack item
|
||||
OP_DUP = 0x76,
|
||||
/// Drops the second-to-top stack item
|
||||
OP_NIP = 0x77,
|
||||
/// Copies the second-to-top stack item, as xA -> AxA
|
||||
OP_OVER = 0x78,
|
||||
/// Pop the top stack element as N. Copy the Nth stack element to the top
|
||||
OP_PICK = 0x79,
|
||||
/// Pop the top stack element as N. Move the Nth stack element to the top
|
||||
OP_ROLL = 0x7a,
|
||||
/// Rotate the top three stack items, as [top next1 next2] -> [next2 top next1]
|
||||
OP_ROT = 0x7b,
|
||||
/// Swap the top two stack items
|
||||
OP_SWAP = 0x7c,
|
||||
/// Copy the top stack item to before the second item, as [top next] -> [top next top]
|
||||
OP_TUCK = 0x7d,
|
||||
/// Fail the script unconditionally, does not even need to be executed
|
||||
OP_CAT = 0x7e,
|
||||
/// Fail the script unconditionally, does not even need to be executed
|
||||
OP_SUBSTR = 0x7f,
|
||||
/// Fail the script unconditionally, does not even need to be executed
|
||||
OP_LEFT = 0x80,
|
||||
/// Fail the script unconditionally, does not even need to be executed
|
||||
OP_RIGHT = 0x81,
|
||||
/// Pushes the length of the top stack item onto the stack
|
||||
OP_SIZE = 0x82,
|
||||
/// Fail the script unconditionally, does not even need to be executed
|
||||
OP_INVERT = 0x83,
|
||||
/// Fail the script unconditionally, does not even need to be executed
|
||||
OP_AND = 0x84,
|
||||
/// Fail the script unconditionally, does not even need to be executed
|
||||
OP_OR = 0x85,
|
||||
/// Fail the script unconditionally, does not even need to be executed
|
||||
OP_XOR = 0x86,
|
||||
/// Pushes 1 if the inputs are exactly equal, 0 otherwise
|
||||
OP_EQUAL = 0x87,
|
||||
/// Returns success if the inputs are exactly equal, failure otherwise
|
||||
OP_EQUALVERIFY = 0x88,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RESERVED1 = 0x89,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RESERVED2 = 0x8a,
|
||||
/// Increment the top stack element in place
|
||||
OP_1ADD = 0x8b,
|
||||
/// Decrement the top stack element in place
|
||||
OP_1SUB = 0x8c,
|
||||
/// Fail the script unconditionally, does not even need to be executed
|
||||
OP_2MUL = 0x8d,
|
||||
/// Fail the script unconditionally, does not even need to be executed
|
||||
OP_2DIV = 0x8e,
|
||||
/// Multiply the top stack item by -1 in place
|
||||
OP_NEGATE = 0x8f,
|
||||
/// Absolute value the top stack item in place
|
||||
OP_ABS = 0x90,
|
||||
/// Map 0 to 1 and everything else to 0, in place
|
||||
OP_NOT = 0x91,
|
||||
/// Map 0 to 0 and everything else to 1, in place
|
||||
OP_0NOTEQUAL = 0x92,
|
||||
/// Pop two stack items and push their sum
|
||||
OP_ADD = 0x93,
|
||||
/// Pop two stack items and push the second minus the top
|
||||
OP_SUB = 0x94,
|
||||
/// Fail the script unconditionally, does not even need to be executed
|
||||
OP_MUL = 0x95,
|
||||
/// Fail the script unconditionally, does not even need to be executed
|
||||
OP_DIV = 0x96,
|
||||
/// Fail the script unconditionally, does not even need to be executed
|
||||
OP_MOD = 0x97,
|
||||
/// Fail the script unconditionally, does not even need to be executed
|
||||
OP_LSHIFT = 0x98,
|
||||
/// Fail the script unconditionally, does not even need to be executed
|
||||
OP_RSHIFT = 0x99,
|
||||
/// Pop the top two stack items and push 1 if both are nonzero, else push 0
|
||||
OP_BOOLAND = 0x9a,
|
||||
/// Pop the top two stack items and push 1 if either is nonzero, else push 0
|
||||
OP_BOOLOR = 0x9b,
|
||||
/// Pop the top two stack items and push 1 if both are numerically equal, else push 0
|
||||
OP_NUMEQUAL = 0x9c,
|
||||
/// Pop the top two stack items and return success if both are numerically equal, else return failure
|
||||
OP_NUMEQUALVERIFY = 0x9d,
|
||||
/// Pop the top two stack items and push 0 if both are numerically equal, else push 1
|
||||
OP_NUMNOTEQUAL = 0x9e,
|
||||
/// Pop the top two items; push 1 if the second is less than the top, 0 otherwise
|
||||
OP_LESSTHAN = 0x9f,
|
||||
/// Pop the top two items; push 1 if the second is greater than the top, 0 otherwise
|
||||
OP_GREATERTHAN = 0xa0,
|
||||
/// Pop the top two items; push 1 if the second is <= the top, 0 otherwise
|
||||
OP_LESSTHANOREQUAL = 0xa1,
|
||||
/// Pop the top two items; push 1 if the second is >= the top, 0 otherwise
|
||||
OP_GREATERTHANOREQUAL = 0xa2,
|
||||
/// Pop the top two items; push the smaller
|
||||
OP_MIN = 0xa3,
|
||||
/// Pop the top two items; push the larger
|
||||
OP_MAX = 0xa4,
|
||||
/// Pop the top three items; if the top is >= the second and < the third, push 1, otherwise push 0
|
||||
OP_WITHIN = 0xa5,
|
||||
/// Pop the top stack item and push its RIPEMD160 hash
|
||||
OP_RIPEMD160 = 0xa6,
|
||||
/// Pop the top stack item and push its SHA1 hash
|
||||
OP_SHA1 = 0xa7,
|
||||
/// Pop the top stack item and push its SHA256 hash
|
||||
OP_SHA256 = 0xa8,
|
||||
/// Pop the top stack item and push its RIPEMD(SHA256) hash
|
||||
OP_HASH160 = 0xa9,
|
||||
/// Pop the top stack item and push its SHA256(SHA256) hash
|
||||
OP_HASH256 = 0xaa,
|
||||
/// Ignore this and everything preceding when deciding what to sign when signature-checking
|
||||
OP_CODESEPARATOR = 0xab,
|
||||
/// https://en.bitcoin.it/wiki/OP_CHECKSIG pushing 1/0 for success/failure
|
||||
OP_CHECKSIG = 0xac,
|
||||
/// https://en.bitcoin.it/wiki/OP_CHECKSIG returning success/failure
|
||||
OP_CHECKSIGVERIFY = 0xad,
|
||||
/// Pop N, N pubkeys, M, M signatures, a dummy (due to bug in reference code), and verify that all M signatures are valid.
|
||||
/// Push 1 for "all valid", 0 otherwise
|
||||
OP_CHECKMULTISIG = 0xae,
|
||||
/// Like the above but return success/failure
|
||||
OP_CHECKMULTISIGVERIFY = 0xaf,
|
||||
/// Does nothing
|
||||
OP_NOP1 = 0xb0,
|
||||
/// Does nothing
|
||||
OP_NOP2 = 0xb1,
|
||||
/// Does nothing
|
||||
OP_NOP3 = 0xb2,
|
||||
/// Does nothing
|
||||
OP_NOP4 = 0xb3,
|
||||
/// Does nothing
|
||||
OP_NOP5 = 0xb4,
|
||||
/// Does nothing
|
||||
OP_NOP6 = 0xb5,
|
||||
/// Does nothing
|
||||
OP_NOP7 = 0xb6,
|
||||
/// Does nothing
|
||||
OP_NOP8 = 0xb7,
|
||||
/// Does nothing
|
||||
OP_NOP9 = 0xb8,
|
||||
/// Does nothing
|
||||
OP_NOP10 = 0xb9,
|
||||
// Every other opcode acts as OP_RETURN
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_186 = 0xba,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_187 = 0xbb,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_188 = 0xbc,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_189 = 0xbd,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_190 = 0xbe,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_191 = 0xbf,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_192 = 0xc0,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_193 = 0xc1,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_194 = 0xc2,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_195 = 0xc3,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_196 = 0xc4,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_197 = 0xc5,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_198 = 0xc6,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_199 = 0xc7,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_200 = 0xc8,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_201 = 0xc9,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_202 = 0xca,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_203 = 0xcb,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_204 = 0xcc,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_205 = 0xcd,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_206 = 0xce,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_207 = 0xcf,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_208 = 0xd0,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_209 = 0xd1,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_210 = 0xd2,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_211 = 0xd3,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_212 = 0xd4,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_213 = 0xd5,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_214 = 0xd6,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_215 = 0xd7,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_216 = 0xd8,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_217 = 0xd9,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_218 = 0xda,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_219 = 0xdb,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_220 = 0xdc,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_221 = 0xdd,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_222 = 0xde,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_223 = 0xdf,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_224 = 0xe0,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_225 = 0xe1,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_226 = 0xe2,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_227 = 0xe3,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_228 = 0xe4,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_229 = 0xe5,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_230 = 0xe6,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_231 = 0xe7,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_232 = 0xe8,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_233 = 0xe9,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_234 = 0xea,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_235 = 0xeb,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_236 = 0xec,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_237 = 0xed,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_238 = 0xee,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_239 = 0xef,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_240 = 0xf0,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_241 = 0xf1,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_242 = 0xf2,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_243 = 0xf3,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_244 = 0xf4,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_245 = 0xf5,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_246 = 0xf6,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_247 = 0xf7,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_248 = 0xf8,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_249 = 0xf9,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_250 = 0xfa,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_251 = 0xfb,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_252 = 0xfc,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_253 = 0xfd,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_254 = 0xfe,
|
||||
/// Synonym for OP_RETURN
|
||||
OP_RETURN_255 = 0xff,
|
||||
}
|
||||
|
||||
impl Opcode {
|
||||
/// Translates a u8 to an Opcode
|
||||
#[inline]
|
||||
pub fn from_u8(b: u8) -> Opcode {
|
||||
unsafe { transmute(b) }
|
||||
}
|
||||
|
||||
/// Classifies an Opcode into a broad class
|
||||
#[inline]
|
||||
pub fn classify(&self) -> super::OpcodeClass {
|
||||
// 17 opcodes
|
||||
if *self == OP_VERIF || *self == OP_VERNOTIF ||
|
||||
*self == OP_CAT || *self == OP_SUBSTR ||
|
||||
*self == OP_LEFT || *self == OP_RIGHT ||
|
||||
*self == OP_INVERT || *self == OP_AND ||
|
||||
*self == OP_OR || *self == OP_XOR ||
|
||||
*self == OP_2MUL || *self == OP_2DIV ||
|
||||
*self == OP_MUL || *self == OP_DIV || *self == OP_MOD ||
|
||||
*self == OP_LSHIFT || *self == OP_RSHIFT {
|
||||
super::IllegalOp
|
||||
// 11 opcodes
|
||||
} else if *self == OP_NOP ||
|
||||
(OP_NOP1 as u8 <= *self as u8 && *self as u8 <= OP_NOP10 as u8) {
|
||||
super::NoOp
|
||||
// 75 opcodes
|
||||
} else if *self == OP_RESERVED || *self == OP_VER || *self == OP_RETURN ||
|
||||
*self == OP_RESERVED1 || *self == OP_RESERVED2 ||
|
||||
*self as u8 >= OP_RETURN_186 as u8 {
|
||||
super::ReturnOp
|
||||
// 1 opcode
|
||||
} else if *self == OP_PUSHNUM_NEG1 {
|
||||
super::PushNum(-1)
|
||||
// 16 opcodes
|
||||
} else if OP_PUSHNUM_1 as u8 <= *self as u8 && *self as u8 <= OP_PUSHNUM_16 as u8 {
|
||||
super::PushNum(1 + OP_PUSHNUM_1 as int - *self as int)
|
||||
// 76 opcodes
|
||||
} else if *self as u8 <= OP_PUSHBYTES_75 as u8 {
|
||||
super::PushBytes(*self as uint)
|
||||
// 60 opcodes
|
||||
} else {
|
||||
super::Ordinary(unsafe { transmute(*self) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<D:SimpleDecoder<E>, E> ConsensusDecodable<D, E> for Opcode {
|
||||
#[inline]
|
||||
fn consensus_decode(d: &mut D) -> Result<Opcode, E> {
|
||||
Ok(Opcode::from_u8(try!(d.read_u8())))
|
||||
}
|
||||
}
|
||||
|
||||
impl<S:SimpleEncoder<E>, E> ConsensusEncodable<S, E> for Opcode {
|
||||
#[inline]
|
||||
fn consensus_encode(&self, s: &mut S) -> Result<(), E> {
|
||||
s.emit_u8(*self as u8)
|
||||
}
|
||||
}
|
||||
|
||||
/// Empty stack is also FALSE
|
||||
pub static OP_FALSE: Opcode = OP_PUSHBYTES_0;
|
||||
/// Number 1 is also TRUE
|
||||
pub static OP_TRUE: Opcode = OP_PUSHNUM_1;
|
||||
}
|
||||
|
||||
/// Broad categories of opcodes with similar behavior
|
||||
#[deriving(PartialEq, Eq, Show)]
|
||||
pub enum OpcodeClass {
|
||||
/// Pushes the given number onto the stack
|
||||
PushNum(int),
|
||||
/// Pushes the given number of bytes onto the stack
|
||||
PushBytes(uint),
|
||||
/// Fails the script if executed
|
||||
ReturnOp,
|
||||
/// Fails the script even if not executed
|
||||
IllegalOp,
|
||||
/// Does nothing
|
||||
NoOp,
|
||||
/// Any opcode not covered above
|
||||
Ordinary(Opcode)
|
||||
}
|
||||
|
||||
macro_rules! ordinary_opcode(
|
||||
($($op:ident),*) => (
|
||||
#[repr(u8)]
|
||||
#[deriving(Clone, PartialEq, Eq, Show)]
|
||||
pub enum Opcode {
|
||||
$( $op = all::$op as u8 ),*
|
||||
}
|
||||
);
|
||||
)
|
||||
|
||||
/// "Ordinary" opcodes -- should be 60 of these
|
||||
ordinary_opcode!(
|
||||
// pushdata
|
||||
OP_PUSHDATA1, OP_PUSHDATA2, OP_PUSHDATA4,
|
||||
// control flow
|
||||
OP_IF, OP_NOTIF, OP_ELSE, OP_ENDIF, OP_VERIFY,
|
||||
// stack
|
||||
OP_TOALTSTACK, OP_FROMALTSTACK,
|
||||
OP_2DROP, OP_2DUP, OP_3DUP, OP_2OVER, OP_2ROT, OP_2SWAP,
|
||||
OP_DROP, OP_DUP, OP_NIP, OP_OVER, OP_PICK, OP_ROLL, OP_ROT, OP_SWAP, OP_TUCK,
|
||||
OP_IFDUP, OP_DEPTH, OP_SIZE,
|
||||
// equality
|
||||
OP_EQUAL, OP_EQUALVERIFY,
|
||||
// arithmetic
|
||||
OP_1ADD, OP_1SUB, OP_NEGATE, OP_ABS, OP_NOT, OP_0NOTEQUAL,
|
||||
OP_ADD, OP_SUB, OP_BOOLAND, OP_BOOLOR,
|
||||
OP_NUMEQUAL, OP_NUMEQUALVERIFY, OP_NUMNOTEQUAL, OP_LESSTHAN,
|
||||
OP_GREATERTHAN, OP_LESSTHANOREQUAL, OP_GREATERTHANOREQUAL,
|
||||
OP_MIN, OP_MAX, OP_WITHIN,
|
||||
// crypto
|
||||
OP_CHECKSIG
|
||||
/*
|
||||
OP_RIPEMD160, OP_SHA1, OP_SHA256, OP_HASH160, OP_HASH256,
|
||||
OP_CODESEPARATOR, OP_CHECKSIG, OP_CHECKSIGVERIFY,
|
||||
OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY
|
||||
*/
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@ use std::char::from_digit;
|
|||
use serialize::json;
|
||||
|
||||
use blockdata::opcodes;
|
||||
use blockdata::opcodes::Opcode;
|
||||
use allops = blockdata::opcodes::all;
|
||||
use network::encodable::{ConsensusDecodable, ConsensusEncodable};
|
||||
use network::serialize::{SimpleDecoder, SimpleEncoder};
|
||||
use util::thinvec::ThinVec;
|
||||
|
@ -36,36 +38,42 @@ use util::thinvec::ThinVec;
|
|||
/// A Bitcoin script
|
||||
pub struct Script(ThinVec<u8>);
|
||||
|
||||
impl Script {
|
||||
/// Creates a new empty script
|
||||
pub fn new() -> Script { Script(ThinVec::new()) }
|
||||
|
||||
/// Adds instructions to push an integer onto the stack. Integers are
|
||||
/// encoded as little-endian signed-magnitude numbers, but there are
|
||||
/// dedicated opcodes to push some small integers.
|
||||
pub fn push_int(&mut self, data: int) {
|
||||
// We can special-case -1, 1-16
|
||||
if data == -1 || (data >= 1 && data <=16) {
|
||||
let &Script(ref mut raw) = self;
|
||||
raw.push(data as u8 + opcodes::TRUE);
|
||||
return;
|
||||
}
|
||||
// We can also special-case zero
|
||||
if data == 0 {
|
||||
let &Script(ref mut raw) = self;
|
||||
raw.push(opcodes::FALSE);
|
||||
return;
|
||||
}
|
||||
// Otherwise encode it as data
|
||||
self.push_scriptint(data);
|
||||
/// Ways that a script might fail. Not everything is split up as
|
||||
/// much as it could be; patches welcome if more detailed errors
|
||||
/// would help you.
|
||||
#[deriving(PartialEq, Eq, Show, Clone)]
|
||||
pub enum ScriptError {
|
||||
/// An OP_ELSE happened while not in an OP_IF tree
|
||||
ElseWithoutIf,
|
||||
/// An OP_ENDIF happened while not in an OP_IF tree
|
||||
EndifWithoutIf,
|
||||
/// An OP_IF happened with an empty stack
|
||||
IfEmptyStack,
|
||||
/// An illegal opcode appeared in the script (does not need to be executed)
|
||||
IllegalOpcode,
|
||||
/// Some opcode expected a parameter, but it was missing or truncated
|
||||
EarlyEndOfScript,
|
||||
/// An OP_RETURN or synonym was executed
|
||||
ExecutedReturn,
|
||||
/// Used OP_PICK with a negative index
|
||||
NegativePick,
|
||||
/// Used OP_ROLL with a negative index
|
||||
NegativeRoll,
|
||||
/// Tried to read an array off the stack as a number when it was more than 4 bytes
|
||||
NumericOverflow,
|
||||
/// Some stack operation was done with an empty stack
|
||||
PopEmptyStack,
|
||||
/// An OP_VERIFY happened with an empty stack
|
||||
VerifyEmptyStack,
|
||||
/// An OP_VERIFY happened with zero on the stack
|
||||
VerifyFailed,
|
||||
}
|
||||
|
||||
/// Adds instructions to push an integer onto the stack, using the explicit
|
||||
/// encoding regardless of the availability of dedicated opcodes.
|
||||
pub fn push_scriptint(&mut self, data: int) {
|
||||
let neg = data < 0;
|
||||
/// Helper to encode an integer in script format
|
||||
fn build_scriptint(n: i64) -> Vec<u8> {
|
||||
let neg = n < 0;
|
||||
|
||||
let mut abs = if neg { -data } else { data } as uint;
|
||||
let mut abs = if neg { -n } else { n } as uint;
|
||||
let mut v = vec![];
|
||||
while abs > 0xFF {
|
||||
v.push((abs & 0xFF) as u8);
|
||||
|
@ -82,8 +90,140 @@ impl Script {
|
|||
abs |= if neg { 0x80 } else { 0 };
|
||||
v.push(abs as u8);
|
||||
}
|
||||
// Finally we put the encoded int onto the stack
|
||||
self.push_slice(v.as_slice());
|
||||
v
|
||||
}
|
||||
|
||||
/// Helper to decode an integer in script format
|
||||
/// Notice that this fails on overflow: the result is the same as in
|
||||
/// bitcoind, that only 4-byte signed-magnitude values may be read as
|
||||
/// numbers. They can be added or subtracted (and a long time ago,
|
||||
/// multiplied and divided), and this may result in numbers which
|
||||
/// can't be written out in 4 bytes or less. This is ok! The number
|
||||
/// just can't be read as a number again.
|
||||
/// This is a bit crazy and subtle, but it makes sense: you can load
|
||||
/// 32-bit numbers and do anything with them, which back when mult/div
|
||||
/// was allowed, could result in up to a 64-bit number. We don't want
|
||||
/// overflow since that's suprising --- and we don't want numbers that
|
||||
/// don't fit in 64 bits (for efficiency on modern processors) so we
|
||||
/// simply say, anything in excess of 32 bits is no longer a number.
|
||||
/// This is basically a ranged type implementation.
|
||||
fn read_scriptint(v: &[u8]) -> Result<i64, ScriptError> {
|
||||
let len = v.len();
|
||||
if len == 0 { return Ok(0); }
|
||||
if len > 4 { return Err(NumericOverflow); }
|
||||
|
||||
let (mut ret, sh) = v.iter()
|
||||
.fold((0, 0), |(acc, sh), n| (acc + (*n as i64 << sh), sh + 8));
|
||||
if v[len - 1] & 0x80 != 0 {
|
||||
ret &= (1 << sh - 1) - 1;
|
||||
ret = -ret;
|
||||
}
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
/// This is like "read_scriptint then map 0 to false and everything
|
||||
/// else as true", except that the overflow rules don't apply.
|
||||
#[inline]
|
||||
fn read_scriptbool(v: &[u8]) -> bool {
|
||||
v.iter().all(|&w| w == 0)
|
||||
}
|
||||
|
||||
/// Helper to read a script uint
|
||||
fn read_uint<'a, I:Iterator<&'a u8>>(mut iter: I, size: uint) -> Result<uint, ScriptError> {
|
||||
let mut ret = 0;
|
||||
for _ in range(0, size) {
|
||||
match iter.next() {
|
||||
Some(&n) => { ret = (ret << 8) + n as uint; }
|
||||
None => { return Err(EarlyEndOfScript); }
|
||||
}
|
||||
}
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
// Macro to translate English stack instructions into Rust code.
|
||||
// All number are references to stack positions: 1 is the top,
|
||||
// 2 is the second-to-top, etc. The numbers do not change within
|
||||
// an opcode; to delete the top two items do `drop 1 drop 2`
|
||||
// rather than `drop 1 drop 1`, which will fail.
|
||||
// This is useful for only about a dozen opcodes, but those ones
|
||||
// were really hard to read and verify -- see OP_PICK and OP_ROLL
|
||||
// for an example of what Rust vector-stack manipulation looks
|
||||
// like.
|
||||
macro_rules! stack_opcode(
|
||||
($stack:ident($min:expr):
|
||||
$(copy $c:expr)*
|
||||
$(swap ($a:expr, $b:expr))*
|
||||
$(perm ($first:expr $(->$i:expr)*) )*
|
||||
$(drop $d:expr)*
|
||||
) => ({
|
||||
// Record top
|
||||
let top = $stack.len();
|
||||
// Check stack size
|
||||
if top < $min { return Err(PopEmptyStack); }
|
||||
// Do copies
|
||||
$( let elem = (*$stack)[top - $c].clone();
|
||||
$stack.push(elem); )*
|
||||
// Do swaps
|
||||
$( $stack.as_mut_slice().swap(top - $a, top - $b); )*
|
||||
// Do permutations
|
||||
$( let first = $first;
|
||||
$( $stack.as_mut_slice().swap(top - first, top - $i); )* )*
|
||||
// Do drops last so that dropped values will be available above
|
||||
$( $stack.remove(top - $d); )*
|
||||
});
|
||||
)
|
||||
|
||||
macro_rules! num_opcode(
|
||||
($stack:ident($($var:ident),*): $op:expr) => ({
|
||||
$(
|
||||
let $var = try!(read_scriptint(match $stack.pop() {
|
||||
Some(elem) => elem,
|
||||
None => { return Err(PopEmptyStack); }
|
||||
}.as_slice()));
|
||||
)*
|
||||
$stack.push(build_scriptint($op));
|
||||
});
|
||||
)
|
||||
|
||||
// OP_VERIFY macro
|
||||
macro_rules! op_verify (
|
||||
($stack:expr) => (
|
||||
match $stack.last().map(|v| read_scriptbool(v.as_slice())) {
|
||||
None => { return Err(VerifyEmptyStack); }
|
||||
Some(false) => { return Err(VerifyFailed); }
|
||||
Some(true) => { $stack.pop(); }
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
impl Script {
|
||||
/// Creates a new empty script
|
||||
pub fn new() -> Script { Script(ThinVec::new()) }
|
||||
|
||||
/// Adds instructions to push an integer onto the stack. Integers are
|
||||
/// encoded as little-endian signed-magnitude numbers, but there are
|
||||
/// dedicated opcodes to push some small integers.
|
||||
pub fn push_int(&mut self, data: i64) {
|
||||
// We can special-case -1, 1-16
|
||||
if data == -1 || (data >= 1 && data <=16) {
|
||||
let &Script(ref mut raw) = self;
|
||||
raw.push(data as u8 + allops::OP_TRUE as u8);
|
||||
return;
|
||||
}
|
||||
// We can also special-case zero
|
||||
if data == 0 {
|
||||
let &Script(ref mut raw) = self;
|
||||
raw.push(allops::OP_FALSE as u8);
|
||||
return;
|
||||
}
|
||||
// Otherwise encode it as data
|
||||
self.push_scriptint(data);
|
||||
}
|
||||
|
||||
/// Adds instructions to push an integer onto the stack, using the explicit
|
||||
/// encoding regardless of the availability of dedicated opcodes.
|
||||
pub fn push_scriptint(&mut self, data: i64) {
|
||||
self.push_slice(build_scriptint(data).as_slice());
|
||||
}
|
||||
|
||||
/// Adds instructions to push some arbitrary data onto the stack
|
||||
|
@ -91,18 +231,18 @@ impl Script {
|
|||
let &Script(ref mut raw) = self;
|
||||
// Start with a PUSH opcode
|
||||
match data.len() {
|
||||
n if n < opcodes::PUSHDATA1 as uint => { raw.push(n as u8); },
|
||||
n if n < opcodes::OP_PUSHDATA1 as uint => { raw.push(n as u8); },
|
||||
n if n < 0x100 => {
|
||||
raw.push(opcodes::PUSHDATA1);
|
||||
raw.push(opcodes::OP_PUSHDATA1 as u8);
|
||||
raw.push(n as u8);
|
||||
},
|
||||
n if n < 0x10000 => {
|
||||
raw.push(opcodes::PUSHDATA2);
|
||||
raw.push(opcodes::OP_PUSHDATA2 as u8);
|
||||
raw.push((n % 0x100) as u8);
|
||||
raw.push((n / 0x100) as u8);
|
||||
},
|
||||
n if n < 0x100000000 => {
|
||||
raw.push(opcodes::PUSHDATA4);
|
||||
raw.push(opcodes::OP_PUSHDATA4 as u8);
|
||||
raw.push((n % 0x100) as u8);
|
||||
raw.push(((n / 0x100) % 0x100) as u8);
|
||||
raw.push(((n / 0x10000) % 0x100) as u8);
|
||||
|
@ -115,9 +255,190 @@ impl Script {
|
|||
}
|
||||
|
||||
/// Adds an individual opcode to the script
|
||||
pub fn push_opcode(&mut self, data: u8) {
|
||||
pub fn push_opcode(&mut self, data: Opcode) {
|
||||
let &Script(ref mut raw) = self;
|
||||
raw.push(data);
|
||||
raw.push(data as u8);
|
||||
}
|
||||
|
||||
/// Evaluate the script, modifying the stack in place
|
||||
pub fn evaluate(&self, stack: &mut Vec<Vec<u8>>) -> Result<(), ScriptError> {
|
||||
let &Script(ref raw) = self;
|
||||
|
||||
let mut iter = raw.iter();
|
||||
let mut exec_stack = vec![true];
|
||||
let mut alt_stack = vec![];
|
||||
|
||||
for byte in iter {
|
||||
let executing = exec_stack.iter().all(|e| *e);
|
||||
// The definitions of all these categories are in opcodes.rs
|
||||
match (executing, allops::Opcode::from_u8(*byte).classify()) {
|
||||
// Illegal operations mean failure regardless of execution state
|
||||
(_, opcodes::IllegalOp) => return Err(IllegalOpcode),
|
||||
// Push number
|
||||
(true, opcodes::PushNum(n)) => stack.push(build_scriptint(n as i64)),
|
||||
// Push data
|
||||
(true, opcodes::PushBytes(n)) => stack.push(iter.take(n).map(|n| *n).collect()),
|
||||
// Return operations mean failure, but only if executed
|
||||
(true, opcodes::ReturnOp) => return Err(ExecutedReturn),
|
||||
// If-statements take effect when not executing
|
||||
(false, opcodes::Ordinary(opcodes::OP_IF)) => exec_stack.push(false),
|
||||
(false, opcodes::Ordinary(opcodes::OP_NOTIF)) => exec_stack.push(false),
|
||||
(false, opcodes::Ordinary(opcodes::OP_ELSE)) => {
|
||||
match exec_stack.mut_last() {
|
||||
Some(ref_e) => { *ref_e = !*ref_e }
|
||||
None => { return Err(ElseWithoutIf); }
|
||||
}
|
||||
}
|
||||
(false, opcodes::Ordinary(opcodes::OP_ENDIF)) => {
|
||||
if exec_stack.pop().is_none() {
|
||||
return Err(EndifWithoutIf);
|
||||
}
|
||||
}
|
||||
// No-ops and non-executed operations do nothing
|
||||
(true, opcodes::NoOp) | (false, _) => {}
|
||||
// Actual opcodes
|
||||
(true, opcodes::Ordinary(op)) => {
|
||||
match op {
|
||||
opcodes::OP_PUSHDATA1 => {
|
||||
let n = try!(read_uint(iter, 1));
|
||||
let read: Vec<u8> = iter.take(n as uint).map(|n| *n).collect();
|
||||
if read.len() < n as uint { return Err(EarlyEndOfScript); }
|
||||
stack.push(read);
|
||||
}
|
||||
opcodes::OP_PUSHDATA2 => {
|
||||
let n = try!(read_uint(iter, 2));
|
||||
let read: Vec<u8> = iter.take(n as uint).map(|n| *n).collect();
|
||||
if read.len() < n as uint { return Err(EarlyEndOfScript); }
|
||||
stack.push(read);
|
||||
}
|
||||
opcodes::OP_PUSHDATA4 => {
|
||||
let n = try!(read_uint(iter, 4));
|
||||
let read: Vec<u8> = iter.take(n as uint).map(|n| *n).collect();
|
||||
if read.len() < n as uint { return Err(EarlyEndOfScript); }
|
||||
stack.push(read);
|
||||
}
|
||||
opcodes::OP_IF => {
|
||||
match stack.pop().map(|v| read_scriptbool(v.as_slice())) {
|
||||
None => { return Err(IfEmptyStack); }
|
||||
Some(b) => exec_stack.push(b)
|
||||
}
|
||||
}
|
||||
opcodes::OP_NOTIF => {
|
||||
match stack.pop().map(|v| read_scriptbool(v.as_slice())) {
|
||||
None => { return Err(IfEmptyStack); }
|
||||
Some(b) => exec_stack.push(!b),
|
||||
}
|
||||
}
|
||||
opcodes::OP_ELSE => {
|
||||
match exec_stack.mut_last() {
|
||||
Some(ref_e) => { *ref_e = !*ref_e }
|
||||
None => { return Err(ElseWithoutIf); }
|
||||
}
|
||||
}
|
||||
opcodes::OP_ENDIF => {
|
||||
if exec_stack.pop().is_none() {
|
||||
return Err(EndifWithoutIf);
|
||||
}
|
||||
}
|
||||
opcodes::OP_VERIFY => op_verify!(stack),
|
||||
opcodes::OP_TOALTSTACK => {
|
||||
match stack.pop() {
|
||||
None => { return Err(PopEmptyStack); }
|
||||
Some(elem) => { alt_stack.push(elem); }
|
||||
}
|
||||
}
|
||||
opcodes::OP_FROMALTSTACK => {
|
||||
match alt_stack.pop() {
|
||||
None => { return Err(PopEmptyStack); }
|
||||
Some(elem) => { stack.push(elem); }
|
||||
}
|
||||
}
|
||||
opcodes::OP_2DROP => stack_opcode!(stack(2): drop 1 drop 2),
|
||||
opcodes::OP_2DUP => stack_opcode!(stack(2): copy 2 copy 1),
|
||||
opcodes::OP_3DUP => stack_opcode!(stack(3): copy 3 copy 2 copy 1),
|
||||
opcodes::OP_2OVER => stack_opcode!(stack(4): copy 4 copy 3),
|
||||
opcodes::OP_2ROT => stack_opcode!(stack(6): perm (1 -> 3 -> 5)
|
||||
perm (2 -> 4 -> 6)),
|
||||
opcodes::OP_2SWAP => stack_opcode!(stack(4): swap (2, 4) swap (1, 3)),
|
||||
opcodes::OP_DROP => stack_opcode!(stack(1): drop 1),
|
||||
opcodes::OP_DUP => stack_opcode!(stack(1): copy 1),
|
||||
opcodes::OP_NIP => stack_opcode!(stack(2): drop 2),
|
||||
opcodes::OP_OVER => stack_opcode!(stack(2): copy 2),
|
||||
opcodes::OP_PICK => {
|
||||
let n = match stack.pop() {
|
||||
Some(data) => try!(read_scriptint(data.as_slice())),
|
||||
None => { return Err(PopEmptyStack); }
|
||||
};
|
||||
if n < 0 { return Err(NegativePick); }
|
||||
let n = n as uint;
|
||||
stack_opcode!(stack(n + 1): copy n + 1)
|
||||
}
|
||||
opcodes::OP_ROLL => {
|
||||
let n = match stack.pop() {
|
||||
Some(data) => try!(read_scriptint(data.as_slice())),
|
||||
None => { return Err(PopEmptyStack); }
|
||||
};
|
||||
if n < 0 { return Err(NegativeRoll); }
|
||||
let n = n as uint;
|
||||
stack_opcode!(stack(n + 1): copy n + 1 drop n + 1)
|
||||
}
|
||||
opcodes::OP_ROT => stack_opcode!(stack(3): perm (1 -> 2 -> 3)),
|
||||
opcodes::OP_SWAP => stack_opcode!(stack(2): swap (1, 2)),
|
||||
opcodes::OP_TUCK => stack_opcode!(stack(2): copy 2 copy 1 drop 2),
|
||||
opcodes::OP_IFDUP => {
|
||||
match stack.last().map(|v| read_scriptbool(v.as_slice())) {
|
||||
None => { return Err(IfEmptyStack); }
|
||||
Some(false) => {}
|
||||
Some(true) => { stack_opcode!(stack(1): copy 1); }
|
||||
}
|
||||
}
|
||||
opcodes::OP_DEPTH => {
|
||||
let len = stack.len() as i64;
|
||||
stack.push(build_scriptint(len));
|
||||
}
|
||||
opcodes::OP_SIZE => {
|
||||
match stack.last().map(|v| v.len() as i64) {
|
||||
None => { return Err(IfEmptyStack); }
|
||||
Some(n) => { stack.push(build_scriptint(n)); }
|
||||
}
|
||||
}
|
||||
opcodes::OP_EQUAL | opcodes::OP_EQUALVERIFY => {
|
||||
if stack.len() < 2 { return Err(PopEmptyStack); }
|
||||
let top = stack.len();
|
||||
let eq = (*stack)[top - 2] == (*stack)[top - 1];
|
||||
stack.push(build_scriptint(if eq { 1 } else { 0 }));
|
||||
if op == opcodes::OP_EQUALVERIFY { op_verify!(stack); }
|
||||
}
|
||||
opcodes::OP_1ADD => num_opcode!(stack(a): a + 1),
|
||||
opcodes::OP_1SUB => num_opcode!(stack(a): a - 1),
|
||||
opcodes::OP_NEGATE => num_opcode!(stack(a): -a),
|
||||
opcodes::OP_ABS => num_opcode!(stack(a): a.abs()),
|
||||
opcodes::OP_NOT => num_opcode!(stack(a): if a == 0 {1} else {0}),
|
||||
opcodes::OP_0NOTEQUAL => num_opcode!(stack(a): if a != 0 {1} else {0}),
|
||||
opcodes::OP_ADD => num_opcode!(stack(b, a): a + b),
|
||||
opcodes::OP_SUB => num_opcode!(stack(b, a): a - b),
|
||||
opcodes::OP_BOOLAND => num_opcode!(stack(b, a): if a != 0 && b != 0 {1} else {0}),
|
||||
opcodes::OP_BOOLOR => num_opcode!(stack(b, a): if a != 0 || b != 0 {1} else {0}),
|
||||
opcodes::OP_NUMEQUAL => num_opcode!(stack(b, a): if a == b {1} else {0}),
|
||||
opcodes::OP_NUMNOTEQUAL => num_opcode!(stack(b, a): if a != b {1} else {0}),
|
||||
opcodes::OP_NUMEQUALVERIFY => {
|
||||
num_opcode!(stack(b, a): if a == b {1} else {0});
|
||||
op_verify!(stack);
|
||||
}
|
||||
opcodes::OP_LESSTHAN => num_opcode!(stack(b, a): if a < b {1} else {0}),
|
||||
opcodes::OP_GREATERTHAN => num_opcode!(stack(b, a): if a > b {1} else {0}),
|
||||
opcodes::OP_LESSTHANOREQUAL => num_opcode!(stack(b, a): if a <= b {1} else {0}),
|
||||
opcodes::OP_GREATERTHANOREQUAL => num_opcode!(stack(b, a): if a >= b {1} else {0}),
|
||||
opcodes::OP_MIN => num_opcode!(stack(b, a): if a < b {a} else {b}),
|
||||
opcodes::OP_MAX => num_opcode!(stack(b, a): if a > b {a} else {b}),
|
||||
opcodes::OP_WITHIN => num_opcode!(stack(c, b, a): if b <= a && a < c {1} else {0}),
|
||||
// TODO: crypto
|
||||
opcodes::OP_CHECKSIG => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -155,8 +476,9 @@ impl<D:SimpleDecoder<E>, E> ConsensusDecodable<D, E> for Script {
|
|||
mod test {
|
||||
use std::io::IoResult;
|
||||
|
||||
use super::{Script, build_scriptint, read_scriptint};
|
||||
|
||||
use network::serialize::{deserialize, serialize};
|
||||
use blockdata::script::Script;
|
||||
use blockdata::opcodes;
|
||||
use util::misc::hex_bytes;
|
||||
use util::thinvec::ThinVec;
|
||||
|
@ -185,8 +507,8 @@ mod test {
|
|||
script.push_slice("NRA4VR".as_bytes()); comp.push_all([6u8, 78, 82, 65, 52, 86, 82]); assert_eq!(script, Script(comp.clone()));
|
||||
|
||||
// opcodes
|
||||
script.push_opcode(opcodes::CHECKSIG); comp.push(0xACu8); assert_eq!(script, Script(comp.clone()));
|
||||
script.push_opcode(opcodes::CHECKSIG); comp.push(0xACu8); assert_eq!(script, Script(comp.clone()));
|
||||
script.push_opcode(opcodes::OP_CHECKSIG); comp.push(0xACu8); assert_eq!(script, Script(comp.clone()));
|
||||
script.push_opcode(opcodes::OP_CHECKSIG); comp.push(0xACu8); assert_eq!(script, Script(comp.clone()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -196,6 +518,22 @@ mod test {
|
|||
assert!(script.is_ok());
|
||||
assert_eq!(serialize(&script.unwrap()), Ok(hex_script));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scriptint_round_trip() {
|
||||
assert_eq!(build_scriptint(-1), vec![0x81]);
|
||||
assert_eq!(build_scriptint(255), vec![255, 0]);
|
||||
assert_eq!(build_scriptint(256), vec![0, 1]);
|
||||
assert_eq!(build_scriptint(257), vec![1, 1]);
|
||||
assert_eq!(build_scriptint(511), vec![255, 1]);
|
||||
for &i in [10, 100, 255, 256, 1000, 10000, 25000, 200000, 5000000, 1000000000,
|
||||
(1 << 31) - 1, -((1 << 31) - 1)].iter() {
|
||||
assert_eq!(Ok(i), read_scriptint(build_scriptint(i).as_slice()));
|
||||
assert_eq!(Ok(-i), read_scriptint(build_scriptint(-i).as_slice()));
|
||||
}
|
||||
assert!(read_scriptint(build_scriptint(1 << 31).as_slice()).is_err());
|
||||
assert!(read_scriptint(build_scriptint(-(1 << 31)).as_slice()).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -98,12 +98,13 @@ mod tests {
|
|||
|
||||
use network::serialize::{deserialize, serialize};
|
||||
|
||||
#[test]
|
||||
fn serialize_test() {
|
||||
assert_eq!(serialize(&Bitcoin).unwrap().as_slice(), "bitcoin".as_bytes());
|
||||
assert_eq!(serialize(&BitcoinTestnet).unwrap().as_slice(), "testnet".as_bytes());
|
||||
assert_eq!(serialize(&Bitcoin).unwrap(), vec![0xf9, 0xbe, 0xb4, 0xd9]);
|
||||
assert_eq!(serialize(&BitcoinTestnet).unwrap(), vec![0x0b, 0x11, 0x09, 0x07]);
|
||||
|
||||
assert_eq!(deserialize(Vec::from_slice("bitcoin".as_bytes())), Ok(Bitcoin));
|
||||
assert_eq!(deserialize(Vec::from_slice("testnet".as_bytes())), Ok(BitcoinTestnet));
|
||||
assert_eq!(deserialize(vec![0xf9, 0xbe, 0xb4, 0xd9]), Ok(Bitcoin));
|
||||
assert_eq!(deserialize(vec![0x0b, 0x11, 0x09, 0x07]), Ok(BitcoinTestnet));
|
||||
|
||||
let bad: Result<Network, _> = deserialize(Vec::from_slice("fakenet".as_bytes()));
|
||||
assert!(bad.is_err());
|
||||
|
|
|
@ -134,7 +134,7 @@ mod tests {
|
|||
use serialize::hex::FromHex;
|
||||
|
||||
use network::serialize::{deserialize, serialize};
|
||||
use util::hash::zero_hash;
|
||||
use std::default::Default;
|
||||
|
||||
#[test]
|
||||
fn getblocks_message_test() {
|
||||
|
@ -146,8 +146,8 @@ mod tests {
|
|||
let real_decode = decode.unwrap();
|
||||
assert_eq!(real_decode.version, 70002);
|
||||
assert_eq!(real_decode.locator_hashes.len(), 1);
|
||||
assert_eq!(real_decode.locator_hashes[0].as_slice(), genhash.as_slice());
|
||||
assert_eq!(real_decode.stop_hash.as_slice(), zero_hash().as_slice());
|
||||
assert_eq!(serialize(&real_decode.locator_hashes[0]), Ok(genhash));
|
||||
assert_eq!(real_decode.stop_hash, Default::default());
|
||||
|
||||
assert_eq!(serialize(&real_decode), Ok(from_sat));
|
||||
}
|
||||
|
@ -162,8 +162,8 @@ mod tests {
|
|||
let real_decode = decode.unwrap();
|
||||
assert_eq!(real_decode.version, 70002);
|
||||
assert_eq!(real_decode.locator_hashes.len(), 1);
|
||||
assert_eq!(real_decode.locator_hashes[0].as_slice(), genhash.as_slice());
|
||||
assert_eq!(real_decode.stop_hash.as_slice(), zero_hash().as_slice());
|
||||
assert_eq!(serialize(&real_decode.locator_hashes[0]), Ok(genhash));
|
||||
assert_eq!(real_decode.stop_hash, Default::default());
|
||||
|
||||
assert_eq!(serialize(&real_decode), Ok(from_sat));
|
||||
}
|
||||
|
|
|
@ -15,14 +15,13 @@
|
|||
//!
|
||||
//! Utility functions related to hashing data, including merkleization
|
||||
|
||||
use collections::bitv::{Bitv, from_bytes};
|
||||
use core::char::from_digit;
|
||||
use core::cmp::min;
|
||||
use std::default::Default;
|
||||
use std::fmt;
|
||||
use std::io::MemWriter;
|
||||
use std::mem::transmute;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::hash;
|
||||
use serialize::json::{mod, ToJson};
|
||||
|
||||
use crypto::digest::Digest;
|
||||
|
@ -36,11 +35,17 @@ use util::uint::Uint256;
|
|||
/// A Bitcoin hash, 32-bytes, computed from x as SHA256(SHA256(x))
|
||||
pub struct Sha256dHash([u8, ..32]);
|
||||
|
||||
/// A boring old Sha256 hash
|
||||
pub struct Sha256Hash([u8, ..32]);
|
||||
|
||||
/// A RIPEMD-160 hash
|
||||
pub struct Ripemd160Hash([u8, ..20]);
|
||||
|
||||
/// A "hasher" which just truncates
|
||||
pub struct DumbHasher;
|
||||
|
||||
// Allow these to be used as a key for Rust's HashMap et. al.
|
||||
impl Hash<u64> for Sha256dHash {
|
||||
impl hash::Hash<u64> for Sha256dHash {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut u64) {
|
||||
use std::mem;
|
||||
|
@ -49,7 +54,7 @@ impl Hash<u64> for Sha256dHash {
|
|||
}
|
||||
}
|
||||
|
||||
impl Hash<u64> for Uint256 {
|
||||
impl hash::Hash<u64> for Uint256 {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut u64) {
|
||||
use std::mem;
|
||||
|
@ -58,7 +63,7 @@ impl Hash<u64> for Uint256 {
|
|||
}
|
||||
}
|
||||
|
||||
impl Hash<u64> for Uint128 {
|
||||
impl hash::Hash<u64> for Uint128 {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut u64) {
|
||||
use std::mem;
|
||||
|
@ -67,9 +72,9 @@ impl Hash<u64> for Uint128 {
|
|||
}
|
||||
}
|
||||
|
||||
impl Hasher<u64> for DumbHasher {
|
||||
impl hash::Hasher<u64> for DumbHasher {
|
||||
#[inline]
|
||||
fn hash<T: Hash<u64>>(&self, value: &T) -> u64 {
|
||||
fn hash<T: hash::Hash<u64>>(&self, value: &T) -> u64 {
|
||||
let mut ret = 0u64;
|
||||
value.hash(&mut ret);
|
||||
ret
|
||||
|
@ -81,13 +86,15 @@ impl Default for DumbHasher {
|
|||
fn default() -> DumbHasher { DumbHasher }
|
||||
}
|
||||
|
||||
/// Returns the all-zeroes "hash"
|
||||
pub fn zero_hash() -> Sha256dHash { Sha256dHash([0u8, ..32]) }
|
||||
impl Default for Sha256dHash {
|
||||
#[inline]
|
||||
fn default() -> Sha256dHash { Sha256dHash([0u8, ..32]) }
|
||||
}
|
||||
|
||||
impl Sha256dHash {
|
||||
/// Create a hash by hashing some data
|
||||
pub fn from_data(data: &[u8]) -> Sha256dHash {
|
||||
let Sha256dHash(mut ret) = zero_hash();
|
||||
let Sha256dHash(mut ret): Sha256dHash = Default::default();
|
||||
let mut sha2 = sha2::Sha256::new();
|
||||
sha2.input(data);
|
||||
sha2.result(ret.as_mut_slice());
|
||||
|
@ -97,24 +104,15 @@ impl Sha256dHash {
|
|||
Sha256dHash(ret)
|
||||
}
|
||||
|
||||
/// Returns a slice containing the bytes of the has
|
||||
pub fn as_slice<'a>(&'a self) -> &'a [u8] {
|
||||
let &Sha256dHash(ref data) = self;
|
||||
data.as_slice()
|
||||
}
|
||||
|
||||
/// Converts a hash to a bit vector
|
||||
pub fn as_bitv(&self) -> Bitv {
|
||||
from_bytes(self.as_slice())
|
||||
}
|
||||
|
||||
/// Converts a hash to a little-endian Uint256
|
||||
#[inline]
|
||||
pub fn into_uint256(self) -> Uint256 {
|
||||
let Sha256dHash(data) = self;
|
||||
unsafe { Uint256(transmute(data)) }
|
||||
}
|
||||
|
||||
/// Converts a hash to a little-endian Uint128, using only the "low" bytes
|
||||
#[inline]
|
||||
pub fn into_uint128(self) -> Uint128 {
|
||||
let Sha256dHash(data) = self;
|
||||
// TODO: this function won't work correctly on big-endian machines
|
||||
|
@ -148,6 +146,7 @@ impl Sha256dHash {
|
|||
}
|
||||
|
||||
impl Clone for Sha256dHash {
|
||||
#[inline]
|
||||
fn clone(&self) -> Sha256dHash {
|
||||
*self
|
||||
}
|
||||
|
@ -181,6 +180,7 @@ impl Index<uint, u8> for Sha256dHash {
|
|||
// little-endian and should be done using the consensus `encodable::ConsensusEncodable`
|
||||
// interface.
|
||||
impl ToJson for Sha256dHash {
|
||||
#[inline]
|
||||
fn to_json(&self) -> json::Json {
|
||||
json::String(self.be_hex_string())
|
||||
}
|
||||
|
@ -207,7 +207,7 @@ impl<D: ::serialize::Decoder<E>, E> ::serialize::Decodable<D, E> for Sha256dHash
|
|||
.map_err(|_| d.error("non-hexadecimal hash string")));
|
||||
let mut ret = [0u8, ..32];
|
||||
for i in range(0, 32) {
|
||||
ret[i] = raw_str[i];
|
||||
ret[i] = raw_str[31 - i];
|
||||
}
|
||||
Ok(Sha256dHash(ret))
|
||||
}
|
||||
|
@ -259,7 +259,7 @@ impl<'a, T: BitcoinHash> MerkleRoot for &'a [T] {
|
|||
fn merkle_root(data: Vec<Sha256dHash>) -> Sha256dHash {
|
||||
// Base case
|
||||
if data.len() < 1 {
|
||||
return zero_hash();
|
||||
return Default::default();
|
||||
}
|
||||
if data.len() < 2 {
|
||||
return data[0];
|
||||
|
@ -290,7 +290,6 @@ impl <T: BitcoinHash> MerkleRoot for Vec<T> {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::prelude::*;
|
||||
use collections::bitv::from_bytes;
|
||||
use std::io::MemWriter;
|
||||
use std::str::from_utf8;
|
||||
use serialize::Encodable;
|
||||
|
@ -298,15 +297,12 @@ mod tests {
|
|||
|
||||
use network::serialize::{serialize, deserialize};
|
||||
use util::hash::Sha256dHash;
|
||||
use util::misc::hex_bytes;
|
||||
|
||||
#[test]
|
||||
fn test_sha256d() {
|
||||
// nb the 5df6... output is the one you get from sha256sum. this is the
|
||||
// "little-endian" hex string since it matches the in-memory representation
|
||||
// of a Uint256 (which is little-endian) after transmutation
|
||||
assert_eq!(Sha256dHash::from_data(&[]).as_slice(),
|
||||
hex_bytes("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456").unwrap().as_slice());
|
||||
assert_eq!(Sha256dHash::from_data(&[]).le_hex_string(),
|
||||
"5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456".to_string());
|
||||
assert_eq!(Sha256dHash::from_data(&[]).be_hex_string(),
|
||||
|
@ -321,12 +317,6 @@ mod tests {
|
|||
assert_eq!(hash, deserial);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hash_to_bitvset() {
|
||||
assert_eq!(Sha256dHash::from_data(&[]).as_bitv(),
|
||||
from_bytes(hex_bytes("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456").unwrap().as_slice()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hash_encode_decode() {
|
||||
let hash = Sha256dHash::from_data(&[]);
|
||||
|
@ -337,7 +327,7 @@ mod tests {
|
|||
}
|
||||
let res = writer.unwrap();
|
||||
assert_eq!(res.as_slice(),
|
||||
"\"5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456\"".as_bytes());
|
||||
"\"56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d\"".as_bytes());
|
||||
assert_eq!(json::decode(from_utf8(res.as_slice()).unwrap()), Ok(hash));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue