Checkpoint commit

27 files changed, 3944 insertions(+), 3812 deletions(-) :} I've
started doing whitespace changes as well, I want everything to
be 4-space tabs from now on.
This commit is contained in:
Andrew Poelstra 2015-04-06 20:51:11 -05:00
parent 811df8a713
commit 200e0fe8e3
28 changed files with 3835 additions and 3741 deletions

View File

@ -22,8 +22,8 @@
use std::num::{Zero, from_u64}; use std::num::{Zero, from_u64};
use util::error; use util;
use util::error::Error::{SpvBadTarget, SpvBadProofOfWork}; use util::Error::{SpvBadTarget, SpvBadProofOfWork};
use util::hash::Sha256dHash; use util::hash::Sha256dHash;
use util::uint::Uint256; use util::uint::Uint256;
use network::encodable::{ConsensusEncodable, VarInt}; use network::encodable::{ConsensusEncodable, VarInt};
@ -97,7 +97,7 @@ impl BlockHeader {
/// Performs an SPV validation of a block, which confirms that the proof-of-work /// Performs an SPV validation of a block, which confirms that the proof-of-work
/// is correct, but does not verify that the transactions are valid or encoded /// is correct, but does not verify that the transactions are valid or encoded
/// correctly. /// correctly.
pub fn spv_validate(&self, required_target: &Uint256) -> Result<(), error::Error> { pub fn spv_validate(&self, required_target: &Uint256) -> Result<(), util::Error> {
let ref target = self.target(); let ref target = self.target();
if target != required_target { if target != required_target {
return Err(SpvBadTarget); return Err(SpvBadTarget);
@ -137,7 +137,7 @@ impl_consensus_encoding!(LoneBlockHeader, header, tx_count);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::io::IoResult; use std::io;
use serialize::hex::FromHex; use serialize::hex::FromHex;
use blockdata::block::Block; use blockdata::block::Block;
@ -151,8 +151,8 @@ mod tests {
let prevhash = "4ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000".from_hex().unwrap(); let prevhash = "4ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000".from_hex().unwrap();
let merkle = "bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914c".from_hex().unwrap(); let merkle = "bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914c".from_hex().unwrap();
let decode: IoResult<Block> = deserialize(some_block.clone()); let decode: io::Result<Block> = deserialize(some_block.clone());
let bad_decode: IoResult<Block> = deserialize(cutoff_block); let bad_decode: io::Result<Block> = deserialize(cutoff_block);
assert!(decode.is_ok()); assert!(decode.is_ok());
assert!(bad_decode.is_err()); assert!(bad_decode.is_err());

View File

@ -33,8 +33,8 @@ use network::constants::Network;
use network::encodable::{ConsensusDecodable, ConsensusEncodable}; use network::encodable::{ConsensusDecodable, ConsensusEncodable};
use network::serialize::{BitcoinHash, SimpleDecoder, SimpleEncoder}; use network::serialize::{BitcoinHash, SimpleDecoder, SimpleEncoder};
use util::BitArray; use util::BitArray;
use util::error; use util;
use util::error::Error::{BlockNotFound, DuplicateHash, PrevHashNotFound}; use util::Error::{BlockNotFound, DuplicateHash, PrevHashNotFound};
use util::uint::Uint256; use util::uint::Uint256;
use util::hash::Sha256dHash; use util::hash::Sha256dHash;
use util::patricia_tree::PatriciaTree; use util::patricia_tree::PatriciaTree;
@ -373,7 +373,7 @@ impl Blockchain {
} }
} }
fn replace_txdata(&mut self, hash: &Uint256, txdata: Vec<Transaction>, has_txdata: bool) -> Result<(), error::Error> { fn replace_txdata(&mut self, hash: &Uint256, txdata: Vec<Transaction>, has_txdata: bool) -> Result<(), util::Error> {
match self.tree.lookup_mut(hash, 256) { match self.tree.lookup_mut(hash, 256) {
Some(existing_block) => { Some(existing_block) => {
unsafe { unsafe {
@ -413,26 +413,26 @@ impl Blockchain {
} }
/// Locates a block in the chain and overwrites its txdata /// Locates a block in the chain and overwrites its txdata
pub fn add_txdata(&mut self, block: Block) -> Result<(), error::Error> { pub fn add_txdata(&mut self, block: Block) -> Result<(), util::Error> {
self.replace_txdata(&block.header.bitcoin_hash().into_le(), block.txdata, true) self.replace_txdata(&block.header.bitcoin_hash().into_le(), block.txdata, true)
} }
/// Locates a block in the chain and removes its txdata /// Locates a block in the chain and removes its txdata
pub fn remove_txdata(&mut self, hash: Sha256dHash) -> Result<(), error::Error> { pub fn remove_txdata(&mut self, hash: Sha256dHash) -> Result<(), util::Error> {
self.replace_txdata(&hash.into_le(), vec![], false) self.replace_txdata(&hash.into_le(), vec![], false)
} }
/// Adds a block header to the chain /// Adds a block header to the chain
pub fn add_header(&mut self, header: BlockHeader) -> Result<(), error::Error> { pub fn add_header(&mut self, header: BlockHeader) -> Result<(), util::Error> {
self.real_add_block(Block { header: header, txdata: vec![] }, false) self.real_add_block(Block { header: header, txdata: vec![] }, false)
} }
/// Adds a block to the chain /// Adds a block to the chain
pub fn add_block(&mut self, block: Block) -> Result<(), error::Error> { pub fn add_block(&mut self, block: Block) -> Result<(), util::Error> {
self.real_add_block(block, true) self.real_add_block(block, true)
} }
fn real_add_block(&mut self, block: Block, has_txdata: bool) -> Result<(), error::Error> { fn real_add_block(&mut self, block: Block, has_txdata: bool) -> Result<(), util::Error> {
// get_prev optimizes the common case where we are extending the best tip // get_prev optimizes the common case where we are extending the best tip
#[inline] #[inline]
fn get_prev<'a>(chain: &'a Blockchain, hash: Sha256dHash) -> Option<NodePtr> { fn get_prev<'a>(chain: &'a Blockchain, hash: Sha256dHash) -> Option<NodePtr> {
@ -618,7 +618,7 @@ impl Blockchain {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::io::IoResult; use std::io;
use blockdata::blockchain::Blockchain; use blockdata::blockchain::Blockchain;
use blockdata::constants::genesis_block; use blockdata::constants::genesis_block;
@ -632,7 +632,7 @@ mod tests {
genesis_block(Bitcoin).header.bitcoin_hash()); genesis_block(Bitcoin).header.bitcoin_hash());
let serial = serialize(&empty_chain); let serial = serialize(&empty_chain);
let deserial: IoResult<Blockchain> = deserialize(serial.unwrap()); let deserial: io::Result<Blockchain> = deserialize(serial.unwrap());
assert!(deserial.is_ok()); assert!(deserial.is_ok());
let read_chain = deserial.unwrap(); let read_chain = deserial.unwrap();

View File

@ -24,6 +24,7 @@ use serde;
// Heavy stick to translate between opcode types // Heavy stick to translate between opcode types
use std::mem::transmute; use std::mem::transmute;
use std::fmt;
use network::serialize::{SimpleDecoder, SimpleEncoder}; use network::serialize::{SimpleDecoder, SimpleEncoder};
use network::encodable::{ConsensusDecodable, ConsensusEncodable}; use network::encodable::{ConsensusDecodable, ConsensusEncodable};
@ -602,6 +603,8 @@ impl All {
} }
} }
display_from_debug!(All);
impl<D: SimpleDecoder> ConsensusDecodable<D> for All { impl<D: SimpleDecoder> ConsensusDecodable<D> for All {
#[inline] #[inline]
fn consensus_decode(d: &mut D) -> Result<All, D::Error> { fn consensus_decode(d: &mut D) -> Result<All, D::Error> {
@ -646,6 +649,8 @@ pub enum Class {
Ordinary(Ordinary) Ordinary(Ordinary)
} }
display_from_debug!(Class);
impl serde::Serialize for Class { impl serde::Serialize for Class {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: serde::Serializer, where S: serde::Serializer,

View File

@ -46,10 +46,16 @@ use network::serialize::{SimpleDecoder, SimpleEncoder, serialize};
use util::hash::Sha256dHash; use util::hash::Sha256dHash;
use util::misc::script_find_and_remove; use util::misc::script_find_and_remove;
#[derive(PartialEq, Eq, Debug, Clone)] #[derive(PartialEq, Eq, Debug)]
/// A Bitcoin script /// A Bitcoin script
pub struct Script(Box<[u8]>); pub struct Script(Box<[u8]>);
impl Clone for Script {
fn clone(&self) -> Script {
Script(self.0.to_vec().into_boxed_slice())
}
}
impl hash::Hash for Script { impl hash::Hash for Script {
#[inline] #[inline]
fn hash<H>(&self, state: &mut H) fn hash<H>(&self, state: &mut H)
@ -132,6 +138,7 @@ pub enum Error {
/// An OP_VERIFY happened with zero on the stack /// An OP_VERIFY happened with zero on the stack
VerifyFailed, VerifyFailed,
} }
display_from_debug!(Error);
/// A rule for validating an abstract stack element /// A rule for validating an abstract stack element
pub struct Validator { pub struct Validator {
@ -200,8 +207,7 @@ fn check_op_equal(elem: &AbstractStackElem, others: &[usize]) -> bool {
} }
} }
fn update_boolean(elem: &mut AbstractStackElem) fn update_boolean(elem: &mut AbstractStackElem) -> Result<(), Error> {
-> Result<(), Error> {
// Test boolean values // Test boolean values
elem.bool_val = Some(true); elem.bool_val = Some(true);
let true_works = elem.validate(); let true_works = elem.validate();
@ -576,10 +582,10 @@ fn update_op_ripemd160(elem: &mut AbstractStackElem, others: &[usize])
let hash = match unsafe { elem.lookup(others[0]) }.raw_value() { let hash = match unsafe { elem.lookup(others[0]) }.raw_value() {
None => None, None => None,
Some(x) => { Some(x) => {
let mut out = [0, ..20]; let mut out = [0; 20];
let mut engine = Ripemd160::new(); let mut engine = Ripemd160::new();
engine.input(x); engine.input(x);
engine.result(out.as_mut_slice()); engine.result(&mut out);
Some(out) Some(out)
} }
}; };
@ -602,10 +608,10 @@ fn update_op_sha1(elem: &mut AbstractStackElem, others: &[usize])
let hash = match unsafe { elem.lookup(others[0]) }.raw_value() { let hash = match unsafe { elem.lookup(others[0]) }.raw_value() {
None => None, None => None,
Some(x) => { Some(x) => {
let mut out = [0, ..20]; let mut out = [0; 20];
let mut engine = Sha1::new(); let mut engine = Sha1::new();
engine.input(x); engine.input(x);
engine.result(out.as_mut_slice()); engine.result(&mut out);
Some(out) Some(out)
} }
}; };
@ -628,8 +634,8 @@ fn update_op_hash160(elem: &mut AbstractStackElem, others: &[usize])
let hash = match unsafe { elem.lookup(others[0]) }.raw_value() { let hash = match unsafe { elem.lookup(others[0]) }.raw_value() {
None => None, None => None,
Some(x) => { Some(x) => {
let mut out1 = [0, ..32]; let mut out1 = [0; 32];
let mut out2 = [0, ..20]; let mut out2 = [0; 20];
let mut engine = Sha256::new(); let mut engine = Sha256::new();
engine.input(x); engine.input(x);
engine.result(&mut out1); engine.result(&mut out1);
@ -658,10 +664,10 @@ fn update_op_sha256(elem: &mut AbstractStackElem, others: &[usize])
let hash = match unsafe { elem.lookup(others[0]) }.raw_value() { let hash = match unsafe { elem.lookup(others[0]) }.raw_value() {
None => None, None => None,
Some(x) => { Some(x) => {
let mut out = [0, ..32]; let mut out = [0; 32];
let mut engine = Sha256::new(); let mut engine = Sha256::new();
engine.input(x); engine.input(x);
engine.result(out.as_mut_slice()); engine.result(&mut out);
Some(out) Some(out)
} }
}; };
@ -684,7 +690,7 @@ fn update_op_hash256(elem: &mut AbstractStackElem, others: &[usize])
let hash = match unsafe { elem.lookup(others[0]) }.raw_value() { let hash = match unsafe { elem.lookup(others[0]) }.raw_value() {
None => None, None => None,
Some(x) => { Some(x) => {
let mut out = [0, ..32]; let mut out = [0; 32];
let mut engine = Sha256::new(); let mut engine = Sha256::new();
engine.input(x); engine.input(x);
engine.result(&mut out); engine.result(&mut out);
@ -1100,16 +1106,6 @@ impl AbstractStack {
} }
} }
/// Lookup an element by index
pub fn get_elem(&self, alloc_index: usize) -> &AbstractStackElem {
&self.alloc[alloc_index]
}
/// Lookup an element by index
pub fn get_elem_mut(&mut self, alloc_index: usize) -> &mut AbstractStackElem {
self.alloc.get_mut(alloc_index)
}
/// Push a copy of an existing element by index /// Push a copy of an existing element by index
pub fn push(&mut self, elem: usize) { pub fn push(&mut self, elem: usize) {
self.stack.push(elem); self.stack.push(elem);
@ -1119,7 +1115,7 @@ impl AbstractStack {
pub fn push_alloc<'a>(&'a mut self, elem: AbstractStackElem) -> &'a mut AbstractStackElem { pub fn push_alloc<'a>(&'a mut self, elem: AbstractStackElem) -> &'a mut AbstractStackElem {
let idx = self.allocate(elem); let idx = self.allocate(elem);
self.stack.push(idx); self.stack.push(idx);
self.alloc.get_mut(idx) &mut self.alloc[idx]
} }
@ -1129,7 +1125,7 @@ impl AbstractStack {
self.push_initial(AbstractStackElem::new_unknown()); self.push_initial(AbstractStackElem::new_unknown());
} }
self.alloc.get_mut(*self.stack.last().unwrap()) &mut self.alloc[*self.stack.last().unwrap()]
} }
/// Obtain a stackref to the current top element /// Obtain a stackref to the current top element
@ -1154,7 +1150,7 @@ impl AbstractStack {
self.push_initial(AbstractStackElem::new_unknown()); self.push_initial(AbstractStackElem::new_unknown());
} }
self.alloc.get_mut(self.stack.pop().unwrap()) &mut self.alloc[self.stack.pop().unwrap()]
} }
@ -1179,23 +1175,6 @@ impl AbstractStack {
} }
} }
/// Immutable view of the current stack as a slice (to be compatible
/// with the `stack_opcode!` macro
pub fn as_slice<'a>(&'a self) -> &'a [usize] {
self.stack.as_slice()
}
/// Immutable view of the current stack as a slice of bytes
pub fn slice_to<'a>(&'a self, n: usize) -> &'a [usize] {
self.stack.slice_to(n)
}
/// Mutable view of the current stack as a slice (to be compatible
/// with the `stack_opcode!` macro
fn as_mut_slice<'a>(&'a mut self) -> &'a mut [usize] {
self.stack.as_mut_slice()
}
/// Length of the current stack /// Length of the current stack
fn len(&self) -> usize { fn len(&self) -> usize {
self.stack.len() self.stack.len()
@ -1207,9 +1186,84 @@ impl AbstractStack {
} }
} }
impl ops::Index<usize> for AbstractStack {
type Output = usize;
#[inline]
fn index(&self, index: usize) -> &usize {
&self.stack[index]
}
}
impl ops::Index<ops::Range<usize>> for AbstractStack {
type Output = [usize];
#[inline]
fn index(&self, index: ops::Range<usize>) -> &[usize] {
&self.stack[index]
}
}
impl ops::Index<ops::RangeTo<usize>> for AbstractStack {
type Output = [usize];
#[inline]
fn index(&self, index: ops::RangeTo<usize>) -> &[usize] {
&self.stack[index]
}
}
impl ops::Index<ops::RangeFrom<usize>> for AbstractStack {
type Output = [usize];
#[inline]
fn index(&self, index: ops::RangeFrom<usize>) -> &[usize] {
&self.stack[index]
}
}
impl ops::Index<ops::RangeFull> for AbstractStack {
type Output = [usize];
#[inline]
fn index(&self, _: ops::RangeFull) -> &[usize] {
&self.stack[..]
}
}
impl ops::IndexMut<usize> for AbstractStack {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut usize {
&mut self.stack[index]
}
}
impl ops::IndexMut<ops::Range<usize>> for AbstractStack {
#[inline]
fn index_mut(&mut self, index: ops::Range<usize>) -> &mut [usize] {
&mut self.stack[index]
}
}
impl ops::IndexMut<ops::RangeTo<usize>> for AbstractStack {
#[inline]
fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut [usize] {
&mut self.stack[index]
}
}
impl ops::IndexMut<ops::RangeFrom<usize>> for AbstractStack {
#[inline]
fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut [usize] {
&mut self.stack[index]
}
}
impl ops::IndexMut<ops::RangeFull> for AbstractStack {
#[inline]
fn index_mut(&mut self, _: ops::RangeFull) -> &mut [usize] {
&mut self.stack[..]
}
}
impl serde::Serialize for Error { impl serde::Serialize for Error {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: serde::Serializer, where S: serde::Serializer
{ {
serializer.visit_str(&self.to_string()) serializer.visit_str(&self.to_string())
} }
@ -1556,10 +1610,10 @@ macro_rules! stack_opcode {
$( let elem = $stack[top - $c].clone(); $( let elem = $stack[top - $c].clone();
$stack.push(elem); )* $stack.push(elem); )*
// Do swaps // Do swaps
$( $stack.as_mut_slice().swap(top - $a, top - $b); )* $( (&mut $stack[..]).swap(top - $a, top - $b); )*
// Do permutations // Do permutations
$( let first = $first; $( let first = $first;
$( $stack.as_mut_slice().swap(top - first, top - $i); )* )* $( (&mut $stack[..]).swap(top - first, top - $i); )* )*
// Do drops last so that dropped values will be available above // Do drops last so that dropped values will be available above
$( $stack.remove(top - $d); )* $( $stack.remove(top - $d); )*
}); });
@ -1569,10 +1623,10 @@ macro_rules! stack_opcode {
macro_rules! num_opcode { macro_rules! num_opcode {
($stack:ident($($var:ident),*): $op:expr) => ({ ($stack:ident($($var:ident),*): $op:expr) => ({
$( $(
let $var = &try!(read_scriptint(match $stack.pop() { let $var = try!(read_scriptint(match $stack.pop() {
Some(elem) => elem, Some(elem) => &elem[..],
None => { return Err(Error::PopEmptyStack); } None => { return Err(Error::PopEmptyStack); }
})[..]); }));
)* )*
$stack.push(MaybeOwned::Owned(build_scriptint($op))); $stack.push(MaybeOwned::Owned(build_scriptint($op)));
// Return a tuple of all the variables // Return a tuple of all the variables
@ -1627,12 +1681,12 @@ macro_rules! hash_opcode {
None => { return Err(Error::PopEmptyStack); } None => { return Err(Error::PopEmptyStack); }
Some(v) => { Some(v) => {
let mut engine = $hash::new(); let mut engine = $hash::new();
engine.input(&v); engine.input(&v[..]);
let mut ret = Vec::with_capacity(engine.output_bits() / 8); let mut ret = Vec::with_capacity(engine.output_bits() / 8);
// Force-set the length even though the vector is uninitialized // Force-set the length even though the vector is uninitialized
// This is OK only because u8 has no destructor // This is OK only because u8 has no destructor
unsafe { ret.set_len(engine.output_bits() / 8); } unsafe { ret.set_len(engine.output_bits() / 8); }
engine.result(ret.as_mut_slice()); engine.result(&mut ret);
$stack.push(MaybeOwned::Owned(ret)); $stack.push(MaybeOwned::Owned(ret));
} }
} }
@ -1642,7 +1696,7 @@ macro_rules! hash_opcode {
// OP_VERIFY macro // OP_VERIFY macro
macro_rules! op_verify { macro_rules! op_verify {
($stack:expr, $err:expr) => ( ($stack:expr, $err:expr) => (
match $stack.last().map(|v| read_scriptbool(&v)) { match $stack.last().map(|v| read_scriptbool(&v[..])) {
None => { return Err(Error::VerifyEmptyStack); } None => { return Err(Error::VerifyEmptyStack); }
Some(false) => { return Err($err); } Some(false) => { return Err($err); }
Some(true) => { $stack.pop(); } Some(true) => { $stack.pop(); }
@ -1730,30 +1784,6 @@ impl Script {
raw.push(data as u8); raw.push(data as u8);
} }
/// Returns a view into the script as a slice
pub fn as_slice(&self) -> &[u8] {
let &Script(ref raw) = self;
raw.as_slice()
}
/// Returns a view into the script as a slice
pub fn slice_to(&self, n: usize) -> &[u8] {
let &Script(ref raw) = self;
raw.slice_to(n)
}
/// Returns a view into the script as a slice
pub fn slice_from(&self, n: usize) -> &[u8] {
let &Script(ref raw) = self;
raw.slice_from(n)
}
/// Returns a view into the script as a slice
pub fn slice(&self, s: usize, e: usize) -> &[u8] {
let &Script(ref raw) = self;
raw.slice(s, e)
}
/// Trace a script /// Trace a script
pub fn trace<'a>(&'a self, stack: &mut Vec<MaybeOwned<'a>>, pub fn trace<'a>(&'a self, stack: &mut Vec<MaybeOwned<'a>>,
input_context: Option<(&Transaction, usize)>) input_context: Option<(&Transaction, usize)>)
@ -1807,7 +1837,6 @@ impl Script {
op_count += 1; op_count += 1;
index += 1; index += 1;
// The definitions of all these categories are in opcodes.rs // The definitions of all these categories are in opcodes.rs
//println!("read {} as {} as {} ... stack before op is {}", byte, opcodes::All::Opcode::from_u8(byte), opcodes::All::Opcode::from_u8(byte).classify(), stack);
match (executing, opcodes::All::Opcode::from_u8(byte).classify()) { match (executing, opcodes::All::Opcode::from_u8(byte).classify()) {
// Illegal operations mean failure regardless of execution state // Illegal operations mean failure regardless of execution state
(_, opcodes::Class::IllegalOp) => return Err(Error::IllegalOpcode), (_, opcodes::Class::IllegalOp) => return Err(Error::IllegalOpcode),
@ -1823,21 +1852,21 @@ impl Script {
} }
(_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA1)) => { (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA1)) => {
if raw.len() < index + 1 { return Err(Error::EarlyEndOfScript); } if raw.len() < index + 1 { return Err(Error::EarlyEndOfScript); }
let n = try!(read_uint(raw.slice_from(index).iter(), 1)); let n = try!(read_uint(&raw[index..], 1));
if raw.len() < index + 1 + n { return Err(Error::EarlyEndOfScript); } if raw.len() < index + 1 + n { return Err(Error::EarlyEndOfScript); }
if executing { stack.push(MaybeOwned::Borrowed(raw.slice(index + 1, index + n + 1))); } if executing { stack.push(MaybeOwned::Borrowed(raw.slice(index + 1, index + n + 1))); }
index += 1 + n; index += 1 + n;
} }
(_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA2)) => { (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA2)) => {
if raw.len() < index + 2 { return Err(Error::EarlyEndOfScript); } if raw.len() < index + 2 { return Err(Error::EarlyEndOfScript); }
let n = try!(read_uint(raw.slice_from(index).iter(), 2)); let n = try!(read_uint(&raw[index..], 2));
if raw.len() < index + 2 + n { return Err(Error::EarlyEndOfScript); } if raw.len() < index + 2 + n { return Err(Error::EarlyEndOfScript); }
if executing { stack.push(MaybeOwned::Borrowed(raw.slice(index + 2, index + n + 2))); } if executing { stack.push(MaybeOwned::Borrowed(raw.slice(index + 2, index + n + 2))); }
index += 2 + n; index += 2 + n;
} }
(_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4)) => { (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4)) => {
if raw.len() < index + 4 { return Err(Error::EarlyEndOfScript); } if raw.len() < index + 4 { return Err(Error::EarlyEndOfScript); }
let n = try!(read_uint(raw.slice_from(index).iter(), 4)); let n = try!(read_uint(&raw[index..], 4));
if raw.len() < index + 4 + n { return Err(Error::EarlyEndOfScript); } if raw.len() < index + 4 + n { return Err(Error::EarlyEndOfScript); }
if executing { stack.push(MaybeOwned::Borrowed(raw.slice(index + 4, index + n + 4))); } if executing { stack.push(MaybeOwned::Borrowed(raw.slice(index + 4, index + n + 4))); }
index += 4 + n; index += 4 + n;
@ -1865,13 +1894,13 @@ impl Script {
// handled above // handled above
} }
opcodes::Ordinary::OP_IF => { opcodes::Ordinary::OP_IF => {
match stack.pop().map(|v| read_scriptbool(&v)) { match stack.pop().map(|v| read_scriptbool(&v[..])) {
None => { return Err(Error::IfEmptyStack); } None => { return Err(Error::IfEmptyStack); }
Some(b) => exec_stack.push(b) Some(b) => exec_stack.push(b)
} }
} }
opcodes::Ordinary::OP_NOTIF => { opcodes::Ordinary::OP_NOTIF => {
match stack.pop().map(|v| read_scriptbool(&v)) { match stack.pop().map(|v| read_scriptbool(&v[..])) {
None => { return Err(Error::IfEmptyStack); } None => { return Err(Error::IfEmptyStack); }
Some(b) => exec_stack.push(!b), Some(b) => exec_stack.push(!b),
} }
@ -1933,7 +1962,7 @@ impl Script {
opcodes::Ordinary::OP_SWAP => stack_opcode!(stack(2): swap (1, 2)), opcodes::Ordinary::OP_SWAP => stack_opcode!(stack(2): swap (1, 2)),
opcodes::Ordinary::OP_TUCK => stack_opcode!(stack(2): copy 2; copy 1 drop 2), opcodes::Ordinary::OP_TUCK => stack_opcode!(stack(2): copy 2; copy 1 drop 2),
opcodes::Ordinary::OP_IFDUP => { opcodes::Ordinary::OP_IFDUP => {
match stack.last().map(|v| read_scriptbool(&v)) { match stack.last().map(|v| read_scriptbool(&v[..])) {
None => { return Err(Error::IfEmptyStack); } None => { return Err(Error::IfEmptyStack); }
Some(false) => {} Some(false) => {}
Some(true) => { stack_opcode!(stack(1): copy 1); } Some(true) => { stack_opcode!(stack(1): copy 1); }
@ -2004,7 +2033,7 @@ impl Script {
// Compute the section of script that needs to be hashed: everything // Compute the section of script that needs to be hashed: everything
// from the last CODESEPARATOR, except the signature itself. // from the last CODESEPARATOR, except the signature itself.
let mut script = raw.slice_from(codeseparator_index).to_vec(); let mut script = (&raw[codeseparator_index..]).to_vec();
let mut remove = Script::new(); let mut remove = Script::new();
remove.push_slice(sig_slice); remove.push_slice(sig_slice);
script_find_and_remove(&mut script, &remove); script_find_and_remove(&mut script, &remove);
@ -2053,7 +2082,7 @@ impl Script {
// Compute the section of script that needs to be hashed: everything // Compute the section of script that needs to be hashed: everything
// from the last CODESEPARATOR, except the signatures themselves. // from the last CODESEPARATOR, except the signatures themselves.
let mut script = raw.slice_from(codeseparator_index).to_vec(); let mut script = (&raw[codeseparator_index..]).to_vec();
for sig in sigs.iter() { for sig in sigs.iter() {
let mut remove = Script::new(); let mut remove = Script::new();
remove.push_slice(&sig); remove.push_slice(&sig);
@ -2148,7 +2177,6 @@ impl Script {
let byte = script[index]; let byte = script[index];
index += 1; index += 1;
// The definitions of all these categories are in opcodes.rs // The definitions of all these categories are in opcodes.rs
//println!("read {} as {} as {}", byte, opcodes::All::Opcode::from_u8(byte), opcodes::All::Opcode::from_u8(byte).classify());
match (executing, opcodes::All::from_u8(byte).classify()) { match (executing, opcodes::All::from_u8(byte).classify()) {
// Illegal operations mean failure regardless of execution state // Illegal operations mean failure regardless of execution state
(_, opcodes::Class::IllegalOp) => return Err(Error::IllegalOpcode), (_, opcodes::Class::IllegalOp) => return Err(Error::IllegalOpcode),
@ -2166,7 +2194,7 @@ impl Script {
} }
(_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA1)) => { (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA1)) => {
if script.len() < index + 1 { return Err(Error::EarlyEndOfScript); } if script.len() < index + 1 { return Err(Error::EarlyEndOfScript); }
let n = match read_uint(script.slice_from(index).iter(), 1) { let n = match read_uint(&script[index..], 1) {
Ok(n) => n, Ok(n) => n,
Err(_) => { return Err(Error::EarlyEndOfScript); } Err(_) => { return Err(Error::EarlyEndOfScript); }
}; };
@ -2178,7 +2206,7 @@ impl Script {
} }
(_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA2)) => { (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA2)) => {
if script.len() < index + 2 { return Err(Error::EarlyEndOfScript); } if script.len() < index + 2 { return Err(Error::EarlyEndOfScript); }
let n = match read_uint(script.slice_from(index).iter(), 2) { let n = match read_uint(&script[index..], 2) {
Ok(n) => n, Ok(n) => n,
Err(_) => { return Err(Error::EarlyEndOfScript); } Err(_) => { return Err(Error::EarlyEndOfScript); }
}; };
@ -2189,7 +2217,7 @@ impl Script {
index += 2 + n; index += 2 + n;
} }
(_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4)) => { (_, opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4)) => {
let n = match read_uint(script.slice_from(index).iter(), 4) { let n = match read_uint(&script[index..], 4) {
Ok(n) => n, Ok(n) => n,
Err(_) => { return Err(Error::EarlyEndOfScript); } Err(_) => { return Err(Error::EarlyEndOfScript); }
}; };
@ -2231,14 +2259,14 @@ impl Script {
let mut stack_true = stack.clone(); let mut stack_true = stack.clone();
// Try pushing false and see what happens // Try pushing false and see what happens
if stack.peek_mut().set_bool_value(false).is_ok() { if stack.peek_mut().set_bool_value(false).is_ok() {
match recurse(script.slice_from(index - 1), stack, exec_stack.clone(), depth + 1) { match recurse(&script[index - 1..], stack, exec_stack.clone(), depth + 1) {
Ok(res) => { return Ok(res); } Ok(res) => { return Ok(res); }
Err(_) => {} Err(_) => {}
} }
} }
// Failing that, push true // Failing that, push true
try!(stack_true.peek_mut().set_bool_value(true)); try!(stack_true.peek_mut().set_bool_value(true));
return recurse(script.slice_from(index - 1), stack_true, exec_stack, depth + 1); return recurse(&script[index - 1..], stack_true, exec_stack, depth + 1);
} }
Some(val) => { Some(val) => {
stack.pop(); stack.pop();
@ -2256,14 +2284,14 @@ impl Script {
let mut stack_true = stack.clone(); let mut stack_true = stack.clone();
// Try pushing false and see what happens // Try pushing false and see what happens
if stack.peek_mut().set_bool_value(false).is_ok() { if stack.peek_mut().set_bool_value(false).is_ok() {
match recurse(script.slice_from(index - 1), stack, exec_stack.clone(), depth + 1) { match recurse(&script[index - 1..], stack, exec_stack.clone(), depth + 1) {
Ok(res) => { return Ok(res); } Ok(res) => { return Ok(res); }
Err(_) => {} Err(_) => {}
} }
} }
// Failing that, push true // Failing that, push true
try!(stack_true.peek_mut().set_bool_value(true)); try!(stack_true.peek_mut().set_bool_value(true));
return recurse(script.slice_from(index - 1), stack_true, exec_stack, depth + 1); return recurse(&script[index - 1..], stack_true, exec_stack, depth + 1);
} }
Some(val) => { Some(val) => {
stack.pop(); stack.pop();
@ -2349,14 +2377,14 @@ impl Script {
let mut stack_true = stack.clone(); let mut stack_true = stack.clone();
// Try pushing false and see what happens // Try pushing false and see what happens
if stack.peek_mut().set_bool_value(false).is_ok() { if stack.peek_mut().set_bool_value(false).is_ok() {
match recurse(script.slice_from(index - 1), stack, exec_stack.clone(), depth + 1) { match recurse(&script[index - 1..], stack, exec_stack.clone(), depth + 1) {
Ok(res) => { return Ok(res); } Ok(res) => { return Ok(res); }
Err(_) => {} Err(_) => {}
} }
} }
// Failing that, push true // Failing that, push true
try!(stack_true.peek_mut().set_bool_value(true)); try!(stack_true.peek_mut().set_bool_value(true));
return recurse(script.slice_from(index - 1), stack_true, exec_stack, depth + 1); return recurse(&script[index - 1..], stack_true, exec_stack, depth + 1);
} }
} }
} }
@ -2476,6 +2504,52 @@ impl Default for Script {
fn default() -> Script { Script(vec![].into_boxed_slice()) } fn default() -> Script { Script(vec![].into_boxed_slice()) }
} }
impl ops::Index<usize> for Script {
type Output = u8;
#[inline]
fn index(&self, index: usize) -> &u8 {
let &Script(ref raw) = self;
&raw[index]
}
}
impl ops::Index<ops::Range<usize>> for Script {
type Output = [u8];
#[inline]
fn index(&self, index: ops::Range<usize>) -> &[u8] {
let &Script(ref raw) = self;
&raw[index]
}
}
impl ops::Index<ops::RangeTo<usize>> for Script {
type Output = [u8];
#[inline]
fn index(&self, index: ops::RangeTo<usize>) -> &[u8] {
let &Script(ref raw) = self;
&raw[index]
}
}
impl ops::Index<ops::RangeFrom<usize>> for Script {
type Output = [u8];
#[inline]
fn index(&self, index: ops::RangeFrom<usize>) -> &[u8] {
let &Script(ref raw) = self;
&raw[index]
}
}
impl ops::Index<ops::RangeFull> for Script {
type Output = [u8];
#[inline]
fn index(&self, _: ops::RangeFull) -> &[u8] {
let &Script(ref raw) = self;
&raw[..]
}
}
// User-facing serialization // User-facing serialization
impl serde::Serialize for Script { impl serde::Serialize for Script {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
@ -2483,8 +2557,8 @@ impl serde::Serialize for Script {
{ {
let &Script(ref raw) = self; let &Script(ref raw) = self;
for dat in raw.iter() { for dat in raw.iter() {
serializer.visit_char(from_digit((dat / 0x10) as usize, 16).unwrap()); serializer.visit_char(from_digit((dat / 0x10) as u32, 16).unwrap());
serializer.visit_char(from_digit((dat & 0x0f) as usize, 16).unwrap()); serializer.visit_char(from_digit((dat & 0x0f) as u32, 16).unwrap());
} }
} }
} }
@ -2507,11 +2581,10 @@ impl<D: SimpleDecoder> ConsensusDecodable<D> for Script {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use std::io::IoResult; use std::io;
use serialize::hex::FromHex; use serialize::hex::FromHex;
use super::{Script, build_scriptint, read_scriptint, read_scriptbool}; use super::{Error, Script, build_scriptint, read_scriptint, read_scriptbool};
use super::{EqualVerifyFailed, NoTransaction, PopEmptyStack};
use super::MaybeOwned::Owned; use super::MaybeOwned::Owned;
use network::serialize::{deserialize, serialize}; use network::serialize::{deserialize, serialize};
@ -2570,7 +2643,7 @@ mod test {
#[test] #[test]
fn script_serialize() { fn script_serialize() {
let hex_script = "6c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52".from_hex().unwrap(); let hex_script = "6c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52".from_hex().unwrap();
let script: IoResult<Script> = deserialize(hex_script.clone()); let script: io::Result<Script> = deserialize(hex_script.clone());
assert!(script.is_ok()); assert!(script.is_ok());
assert_eq!(serialize(&script.unwrap()), Ok(hex_script)); assert_eq!(serialize(&script.unwrap()), Ok(hex_script));
} }

View File

@ -180,7 +180,7 @@ impl TxIn {
} }
match stack.pop() { match stack.pop() {
Some(v) => { Some(v) => {
if !read_scriptbool(v.as_slice()) { if !read_scriptbool(&v[..]) {
return Err(Error::ScriptReturnedFalse); return Err(Error::ScriptReturnedFalse);
} }
} }
@ -193,7 +193,7 @@ impl TxIn {
} }
match p2sh_stack.pop() { match p2sh_stack.pop() {
Some(v) => { Some(v) => {
if !read_scriptbool(v.as_slice()) { if !read_scriptbool(&v[..]) {
return Err(Error::P2shScriptReturnedFalse); return Err(Error::P2shScriptReturnedFalse);
} }
} }
@ -261,7 +261,7 @@ impl Transaction {
err.map(|e| trace.error = Some(Error::OutputScriptFailure(e))); err.map(|e| trace.error = Some(Error::OutputScriptFailure(e)));
match stack.pop() { match stack.pop() {
Some(v) => { Some(v) => {
if !read_scriptbool(v.as_slice()) { if !read_scriptbool(&v[..]) {
trace.error = Some(Error::ScriptReturnedFalse); trace.error = Some(Error::ScriptReturnedFalse);
} }
} }
@ -273,7 +273,7 @@ impl Transaction {
err.map(|e| trace.error = Some(Error::P2shScriptFailure(e))); err.map(|e| trace.error = Some(Error::P2shScriptFailure(e)));
match p2sh_stack.pop() { match p2sh_stack.pop() {
Some(v) => { Some(v) => {
if !read_scriptbool(v.as_slice()) { if !read_scriptbool(&v[..]) {
trace.error = Some(Error::P2shScriptReturnedFalse); trace.error = Some(Error::P2shScriptReturnedFalse);
} }
} }
@ -295,7 +295,7 @@ impl Transaction {
impl BitcoinHash for Transaction { impl BitcoinHash for Transaction {
fn bitcoin_hash(&self) -> Sha256dHash { fn bitcoin_hash(&self) -> Sha256dHash {
use network::serialize::serialize; use network::serialize::serialize;
Sha256dHash::from_data(serialize(self).unwrap().as_slice()) Sha256dHash::from_data(&serialize(self).unwrap())
} }
} }
@ -307,7 +307,7 @@ impl_consensus_encoding!(Transaction, version, input, output, lock_time);
mod tests { mod tests {
use super::{Transaction, TxIn}; use super::{Transaction, TxIn};
use std::io::IoResult; use std::io;
use network::serialize::BitcoinHash; use network::serialize::BitcoinHash;
use network::serialize::deserialize; use network::serialize::deserialize;
@ -315,14 +315,14 @@ mod tests {
#[test] #[test]
fn test_txin() { fn test_txin() {
let txin: IoResult<TxIn> = deserialize(hex_bytes("a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff").unwrap()); let txin: io::Result<TxIn> = deserialize(hex_bytes("a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff").unwrap());
assert!(txin.is_ok()); assert!(txin.is_ok());
} }
#[test] #[test]
fn test_transaction() { fn test_transaction() {
let hex_tx = hex_bytes("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap(); let hex_tx = hex_bytes("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap();
let tx: IoResult<Transaction> = deserialize(hex_tx); let tx: io::Result<Transaction> = deserialize(hex_tx);
assert!(tx.is_ok()); assert!(tx.is_ok());
let realtx = tx.unwrap(); let realtx = tx.unwrap();
// All these tests aren't really needed because if they fail, the hash check at the end // All these tests aren't really needed because if they fail, the hash check at the end

View File

@ -423,7 +423,7 @@ impl UtxoSet {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::prelude::*; use std::prelude::*;
use std::io::IoResult; use std::io;
use serialize::hex::FromHex; use serialize::hex::FromHex;
use super::{UtxoSet, ValidationLevel}; use super::{UtxoSet, ValidationLevel};
@ -472,7 +472,7 @@ mod tests {
// Serialize/deserialize the resulting UTXO set // Serialize/deserialize the resulting UTXO set
let serial = serialize(&empty_set).unwrap(); let serial = serialize(&empty_set).unwrap();
let deserial: IoResult<UtxoSet> = deserialize(serial.clone()); let deserial: io::Result<UtxoSet> = deserialize(serial.clone());
assert!(deserial.is_ok()); assert!(deserial.is_ok());
// Check that all outputs are there // Check that all outputs are there
@ -492,7 +492,7 @@ mod tests {
} }
} }
let deserial_again: IoResult<UtxoSet> = deserialize(serial); let deserial_again: io::Result<UtxoSet> = deserialize(serial);
let mut read_again = deserial_again.unwrap(); let mut read_again = deserial_again.unwrap();
assert!(read_again.rewind(&new_block)); assert!(read_again.rewind(&new_block));
assert_eq!(read_again.n_utxos(), 0); assert_eq!(read_again.n_utxos(), 0);

View File

@ -56,34 +56,6 @@ macro_rules! impl_newtype_consensus_encoding {
macro_rules! impl_array_newtype { macro_rules! impl_array_newtype {
($thing:ident, $ty:ty, $len:expr) => { ($thing:ident, $ty:ty, $len:expr) => {
impl $thing { impl $thing {
#[inline]
/// Provides an immutable view into the object
pub fn as_slice<'a>(&'a self) -> &'a [$ty] {
let &$thing(ref dat) = self;
dat.as_slice()
}
#[inline]
/// Provides an immutable view into the object from index `s` inclusive to `e` exclusive
pub fn slice<'a>(&'a self, s: usize, e: usize) -> &'a [$ty] {
let &$thing(ref dat) = self;
dat.slice(s, e)
}
#[inline]
/// Provides an immutable view into the object, up to index `n` exclusive
pub fn slice_to<'a>(&'a self, n: usize) -> &'a [$ty] {
let &$thing(ref dat) = self;
dat.slice_to(n)
}
#[inline]
/// Provides an immutable view into the object, starting from index `n`
pub fn slice_from<'a>(&'a self, n: usize) -> &'a [$ty] {
let &$thing(ref dat) = self;
dat.slice_from(n)
}
#[inline] #[inline]
/// Converts the object to a raw pointer /// Converts the object to a raw pointer
pub fn as_ptr(&self) -> *const $ty { pub fn as_ptr(&self) -> *const $ty {
@ -94,7 +66,7 @@ macro_rules! impl_array_newtype {
#[inline] #[inline]
/// Converts the object to a mutable raw pointer /// Converts the object to a mutable raw pointer
pub fn as_mut_ptr(&mut self) -> *mut $ty { pub fn as_mut_ptr(&mut self) -> *mut $ty {
let &$thing(ref mut dat) = self; let &mut $thing(ref mut dat) = self;
dat.as_mut_ptr() dat.as_mut_ptr()
} }
@ -109,8 +81,8 @@ macro_rules! impl_array_newtype {
use std::intrinsics::copy_nonoverlapping; use std::intrinsics::copy_nonoverlapping;
use std::mem; use std::mem;
let mut ret: $thing = mem::uninitialized(); let mut ret: $thing = mem::uninitialized();
copy_nonoverlapping(ret.as_mut_ptr(), copy_nonoverlapping(data.as_ptr(),
data.as_ptr(), ret.as_mut_ptr(),
mem::size_of::<$thing>()); mem::size_of::<$thing>());
ret ret
} }
@ -133,7 +105,7 @@ macro_rules! impl_array_newtype {
#[inline] #[inline]
fn index(&self, index: ::std::ops::Range<usize>) -> &[$ty] { fn index(&self, index: ::std::ops::Range<usize>) -> &[$ty] {
let &$thing(ref dat) = self; let &$thing(ref dat) = self;
&dat[index.start..index.end] &dat[index]
} }
} }
@ -143,7 +115,7 @@ macro_rules! impl_array_newtype {
#[inline] #[inline]
fn index(&self, index: ::std::ops::RangeTo<usize>) -> &[$ty] { fn index(&self, index: ::std::ops::RangeTo<usize>) -> &[$ty] {
let &$thing(ref dat) = self; let &$thing(ref dat) = self;
&dat[..index.end] &dat[index]
} }
} }
@ -153,7 +125,7 @@ macro_rules! impl_array_newtype {
#[inline] #[inline]
fn index(&self, index: ::std::ops::RangeFrom<usize>) -> &[$ty] { fn index(&self, index: ::std::ops::RangeFrom<usize>) -> &[$ty] {
let &$thing(ref dat) = self; let &$thing(ref dat) = self;
&dat[index.start..] &dat[index]
} }
} }
@ -170,7 +142,7 @@ macro_rules! impl_array_newtype {
impl PartialEq for $thing { impl PartialEq for $thing {
#[inline] #[inline]
fn eq(&self, other: &$thing) -> bool { fn eq(&self, other: &$thing) -> bool {
self.as_slice() == other.as_slice() &self[..] == &other[..]
} }
} }
@ -179,7 +151,24 @@ macro_rules! impl_array_newtype {
impl Clone for $thing { impl Clone for $thing {
#[inline] #[inline]
fn clone(&self) -> $thing { fn clone(&self) -> $thing {
$thing::from_slice(self.as_slice()) $thing::from_slice(&self[..])
}
}
impl ::std::hash::Hash for $thing {
#[inline]
fn hash<H>(&self, state: &mut H)
where H: ::std::hash::Hasher
{
(&self[..]).hash(state);
}
fn hash_slice<H>(data: &[$thing], state: &mut H)
where H: ::std::hash::Hasher
{
for d in data.iter() {
(&d[..]).hash(state);
}
} }
} }
} }
@ -209,7 +198,10 @@ macro_rules! impl_array_newtype_encodable {
use std::mem; use std::mem;
let mut ret: [$ty; $len] = mem::uninitialized(); let mut ret: [$ty; $len] = mem::uninitialized();
for i in 0..$len { for i in 0..$len {
ret[i] = try!(v.visit()); ret[i] = match try!(v.visit()) {
Some(c) => c,
None => return Err(::serde::de::Error::end_of_stream_error())
};
} }
Ok($thing(ret)) Ok($thing(ret))
} }
@ -236,7 +228,17 @@ macro_rules! impl_array_newtype_show {
($thing:ident) => { ($thing:ident) => {
impl ::std::fmt::Debug for $thing { impl ::std::fmt::Debug for $thing {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, concat!(stringify!($thing), "({})"), self.as_slice()) write!(f, concat!(stringify!($thing), "({:?})"), &self[..])
}
}
}
}
macro_rules! display_from_debug {
($thing:ident) => {
impl ::std::fmt::Display for $thing {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
::std::fmt::Debug::fmt(self, f)
} }
} }
} }

View File

@ -98,6 +98,14 @@ macro_rules! user_enum {
} }
} }
impl ::std::fmt::Display for $name {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
f.pad(match *self {
$($elem => $txt),*
})
}
}
impl ::serde::Deserialize for $name { impl ::serde::Deserialize for $name {
#[inline] #[inline]
fn deserialize<D>(d: &mut D) -> Result<$name, D::Error> fn deserialize<D>(d: &mut D) -> Result<$name, D::Error>

View File

@ -64,8 +64,8 @@ impl<D: SimpleDecoder> ConsensusDecodable<D> for Address {
impl fmt::Debug for Address { impl fmt::Debug for Address {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// TODO: render services and hex-ize address // TODO: render services and hex-ize address
write!(f, "Address {{services: {}, address: {}, port: {}}}", write!(f, "Address {{services: {:?}, address: {:?}, port: {:?}}}",
self.services, self.address.as_slice(), self.port) self.services, &self.address[..], self.port)
} }
} }
@ -75,8 +75,8 @@ impl Clone for Address {
use std::intrinsics::copy_nonoverlapping; use std::intrinsics::copy_nonoverlapping;
use std::mem; use std::mem;
let mut ret = mem::uninitialized(); let mut ret = mem::uninitialized();
copy_nonoverlapping(&mut ret, copy_nonoverlapping(self,
self, &mut ret,
mem::size_of::<Address>()); mem::size_of::<Address>());
ret ret
} }
@ -86,7 +86,7 @@ impl Clone for Address {
impl PartialEq for Address { impl PartialEq for Address {
fn eq(&self, other: &Address) -> bool { fn eq(&self, other: &Address) -> bool {
self.services == other.services && self.services == other.services &&
self.address.as_slice() == other.address.as_slice() && &self.address[..] == &other.address[..] &&
self.port == other.port self.port == other.port
} }
} }
@ -97,7 +97,7 @@ impl Eq for Address {}
mod test { mod test {
use super::Address; use super::Address;
use std::io::IoResult; use std::io;
use network::serialize::{deserialize, serialize}; use network::serialize::{deserialize, serialize};
@ -114,7 +114,7 @@ mod test {
#[test] #[test]
fn deserialize_address_test() { fn deserialize_address_test() {
let mut addr: IoResult<Address> = deserialize(vec![1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, let mut addr: io::Result<Address> = deserialize(vec![1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x0a, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x0a, 0,
0, 1, 0x20, 0x8d]); 0, 1, 0x20, 0x8d]);
assert!(addr.is_ok()); assert!(addr.is_ok());

View File

@ -42,7 +42,7 @@ pub fn magic(network: Network) -> u32 {
match network { match network {
Network::Bitcoin => 0xD9B4BEF9, Network::Bitcoin => 0xD9B4BEF9,
Network::Testnet => 0x0709110B Network::Testnet => 0x0709110B
// Note: any new entries here must be added to `deserialize` below // Note: any new entries here must be added to `consensus_decode` below
} }
} }
@ -60,7 +60,7 @@ impl<D: SimpleDecoder> ConsensusDecodable<D> for Network {
match magic { match magic {
0xD9B4BEF9 => Ok(Network::Bitcoin), 0xD9B4BEF9 => Ok(Network::Bitcoin),
0x0709110B => Ok(Network::Testnet), 0x0709110B => Ok(Network::Testnet),
x => Err(d.error(format!("Unknown network (magic {:x})", x).as_slice())) x => Err(d.error(format!("Unknown network (magic {:x})", x)))
} }
} }
} }

View File

@ -31,7 +31,8 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::default::Default; use std::default::Default;
use std::hash::{Hash, Hasher}; use std::hash::Hash;
use std::collections::hash_state::HashState;
use std::u32; use std::u32;
use util::hash::Sha256dHash; use util::hash::Sha256dHash;
@ -91,12 +92,11 @@ impl<S: SimpleEncoder> ConsensusEncodable<S> for i64 {
impl<S: SimpleEncoder> ConsensusEncodable<S> for VarInt { impl<S: SimpleEncoder> ConsensusEncodable<S> for VarInt {
#[inline] #[inline]
fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> {
let &VarInt(n) = self; match self.0 {
match n { 0...0xFC => { (self.0 as u8).consensus_encode(s) }
0...0xFC => { (n as u8).consensus_encode(s) } 0xFD...0xFFFF => { try!(s.emit_u8(0xFD)); (self.0 as u16).consensus_encode(s) }
0xFD...0xFFFF => { try!(s.emit_u8(0xFD)); (n as u16).consensus_encode(s) } 0x10000...0xFFFFFFFF => { try!(s.emit_u8(0xFE)); (self.0 as u32).consensus_encode(s) }
0x10000...0xFFFFFFFF => { try!(s.emit_u8(0xFE)); (n as u32).consensus_encode(s) } _ => { try!(s.emit_u8(0xFF)); (self.0 as u64).consensus_encode(s) }
_ => { try!(s.emit_u8(0xFF)); (n as u64).consensus_encode(s) }
} }
} }
} }
@ -166,7 +166,8 @@ impl<S: SimpleEncoder> ConsensusEncodable<S> for String {
impl<D: SimpleDecoder> ConsensusDecodable<D> for String { impl<D: SimpleDecoder> ConsensusDecodable<D> for String {
#[inline] #[inline]
fn consensus_decode(d: &mut D) -> Result<String, D::Error> { fn consensus_decode(d: &mut D) -> Result<String, D::Error> {
String::from_utf8(try!(ConsensusDecodable::consensus_decode(d))).map_err(|_| d.error("String was not valid UTF8")) String::from_utf8(try!(ConsensusDecodable::consensus_decode(d)))
.map_err(|_| d.error("String was not valid UTF8".to_string()))
} }
} }
@ -216,7 +217,7 @@ impl<'a, S: SimpleEncoder, T: ConsensusEncodable<S>> ConsensusEncodable<S> for &
// Vectors // Vectors
impl<S: SimpleEncoder, T: ConsensusEncodable<S>> ConsensusEncodable<S> for Vec<T> { impl<S: SimpleEncoder, T: ConsensusEncodable<S>> ConsensusEncodable<S> for Vec<T> {
#[inline] #[inline]
fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { self.as_slice().consensus_encode(s) } fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { (&self[..]).consensus_encode(s) }
} }
impl<D: SimpleDecoder, T: ConsensusDecodable<D>> ConsensusDecodable<D> for Vec<T> { impl<D: SimpleDecoder, T: ConsensusDecodable<D>> ConsensusDecodable<D> for Vec<T> {
@ -285,11 +286,10 @@ fn sha2_checksum(data: &[u8]) -> [u8; 4] {
impl<S: SimpleEncoder> ConsensusEncodable<S> for CheckedData { impl<S: SimpleEncoder> ConsensusEncodable<S> for CheckedData {
#[inline] #[inline]
fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> { fn consensus_encode(&self, s: &mut S) -> Result<(), S::Error> {
let &CheckedData(ref data) = self; try!((self.0.len() as u32).consensus_encode(s));
try!((data.len() as u32).consensus_encode(s)); try!(sha2_checksum(&self.0).consensus_encode(s));
try!(sha2_checksum(data.as_slice()).consensus_encode(s));
// We can't just pass to the slice encoder since it'll insert a length // We can't just pass to the slice encoder since it'll insert a length
for ch in data.iter() { for ch in self.0.iter() {
try!(ch.consensus_encode(s)); try!(ch.consensus_encode(s));
} }
Ok(()) Ok(())
@ -303,9 +303,9 @@ impl<D: SimpleDecoder> ConsensusDecodable<D> for CheckedData {
let checksum: [u8; 4] = try!(ConsensusDecodable::consensus_decode(d)); let checksum: [u8; 4] = try!(ConsensusDecodable::consensus_decode(d));
let mut ret = Vec::with_capacity(len as usize); let mut ret = Vec::with_capacity(len as usize);
for _ in 0..len { ret.push(try!(ConsensusDecodable::consensus_decode(d))); } for _ in 0..len { ret.push(try!(ConsensusDecodable::consensus_decode(d))); }
let expected_checksum = sha2_checksum(ret.as_slice()); let expected_checksum = sha2_checksum(&ret);
if expected_checksum != checksum { if expected_checksum != checksum {
Err(d.error("bad checksum")) Err(d.error(format!("bad checksum {:?} (expected {:?})", checksum, expected_checksum)))
} else { } else {
Ok(CheckedData(ret)) Ok(CheckedData(ret))
} }
@ -356,7 +356,7 @@ impl<D: SimpleDecoder, T: ConsensusDecodable<D>> ConsensusDecodable<D> for Box<T
// HashMap // HashMap
impl<S, K, V, H> ConsensusEncodable<S> for HashMap<K, V, H> impl<S, K, V, H> ConsensusEncodable<S> for HashMap<K, V, H>
where S: SimpleEncoder, where S: SimpleEncoder,
H: Hasher + Default, H: HashState + Default,
K: ConsensusEncodable<S> + Eq + Hash, K: ConsensusEncodable<S> + Eq + Hash,
V: ConsensusEncodable<S> V: ConsensusEncodable<S>
{ {
@ -373,7 +373,7 @@ impl<S, K, V, H> ConsensusEncodable<S> for HashMap<K, V, H>
impl<D, K, V, H> ConsensusDecodable<D> for HashMap<K, V, H> impl<D, K, V, H> ConsensusDecodable<D> for HashMap<K, V, H>
where D: SimpleDecoder, where D: SimpleDecoder,
H: Hasher + Default, H: HashState + Default,
K: ConsensusDecodable<D> + Eq + Hash, K: ConsensusDecodable<D> + Eq + Hash,
V: ConsensusDecodable<D> V: ConsensusDecodable<D>
{ {
@ -381,7 +381,7 @@ impl<D, K, V, H> ConsensusDecodable<D> for HashMap<K, V, H>
fn consensus_decode(d: &mut D) -> Result<HashMap<K, V, H>, D::Error> { fn consensus_decode(d: &mut D) -> Result<HashMap<K, V, H>, D::Error> {
let VarInt(len): VarInt = try!(ConsensusDecodable::consensus_decode(d)); let VarInt(len): VarInt = try!(ConsensusDecodable::consensus_decode(d));
let mut ret = HashMap::with_capacity_and_hasher(len as usize, Default::default()); let mut ret = HashMap::with_capacity_and_hash_state(len as usize, Default::default());
for _ in 0..len { for _ in 0..len {
ret.insert(try!(ConsensusDecodable::consensus_decode(d)), ret.insert(try!(ConsensusDecodable::consensus_decode(d)),
try!(ConsensusDecodable::consensus_decode(d))); try!(ConsensusDecodable::consensus_decode(d)));
@ -397,7 +397,7 @@ impl<D, K, V, H> ConsensusDecodable<D> for HashMap<K, V, H>
mod tests { mod tests {
use super::{CheckedData, VarInt}; use super::{CheckedData, VarInt};
use std::io::IoResult; use std::io;
use network::serialize::{deserialize, serialize}; use network::serialize::{deserialize, serialize};
@ -499,29 +499,29 @@ mod tests {
assert_eq!(deserialize(vec![0x01u8, 0x02]), Ok(0x0201u16)); assert_eq!(deserialize(vec![0x01u8, 0x02]), Ok(0x0201u16));
assert_eq!(deserialize(vec![0xABu8, 0xCD]), Ok(0xCDABu16)); assert_eq!(deserialize(vec![0xABu8, 0xCD]), Ok(0xCDABu16));
assert_eq!(deserialize(vec![0xA0u8, 0x0D]), Ok(0xDA0u16)); assert_eq!(deserialize(vec![0xA0u8, 0x0D]), Ok(0xDA0u16));
let failure16: IoResult<u16> = deserialize(vec![1u8]); let failure16: io::Result<u16> = deserialize(vec![1u8]);
assert!(failure16.is_err()); assert!(failure16.is_err());
// u32 // u32
assert_eq!(deserialize(vec![0xABu8, 0xCD, 0, 0]), Ok(0xCDABu32)); assert_eq!(deserialize(vec![0xABu8, 0xCD, 0, 0]), Ok(0xCDABu32));
assert_eq!(deserialize(vec![0xA0u8, 0x0D, 0xAB, 0xCD]), Ok(0xCDAB0DA0u32)); assert_eq!(deserialize(vec![0xA0u8, 0x0D, 0xAB, 0xCD]), Ok(0xCDAB0DA0u32));
let failure32: IoResult<u32> = deserialize(vec![1u8, 2, 3]); let failure32: io::Result<u32> = deserialize(vec![1u8, 2, 3]);
assert!(failure32.is_err()); assert!(failure32.is_err());
// TODO: test negative numbers // TODO: test negative numbers
assert_eq!(deserialize(vec![0xABu8, 0xCD, 0, 0]), Ok(0xCDABi32)); assert_eq!(deserialize(vec![0xABu8, 0xCD, 0, 0]), Ok(0xCDABi32));
assert_eq!(deserialize(vec![0xA0u8, 0x0D, 0xAB, 0x2D]), Ok(0x2DAB0DA0i32)); assert_eq!(deserialize(vec![0xA0u8, 0x0D, 0xAB, 0x2D]), Ok(0x2DAB0DA0i32));
let failurei32: IoResult<i32> = deserialize(vec![1u8, 2, 3]); let failurei32: io::Result<i32> = deserialize(vec![1u8, 2, 3]);
assert!(failurei32.is_err()); assert!(failurei32.is_err());
// u64 // u64
assert_eq!(deserialize(vec![0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]), Ok(0xCDABu64)); assert_eq!(deserialize(vec![0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]), Ok(0xCDABu64));
assert_eq!(deserialize(vec![0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]), Ok(0x99000099CDAB0DA0u64)); assert_eq!(deserialize(vec![0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]), Ok(0x99000099CDAB0DA0u64));
let failure64: IoResult<u64> = deserialize(vec![1u8, 2, 3, 4, 5, 6, 7]); let failure64: io::Result<u64> = deserialize(vec![1u8, 2, 3, 4, 5, 6, 7]);
assert!(failure64.is_err()); assert!(failure64.is_err());
// TODO: test negative numbers // TODO: test negative numbers
assert_eq!(deserialize(vec![0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]), Ok(0xCDABi64)); assert_eq!(deserialize(vec![0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]), Ok(0xCDABi64));
assert_eq!(deserialize(vec![0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]), Ok(-0x66ffff663254f260i64)); assert_eq!(deserialize(vec![0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]), Ok(-0x66ffff663254f260i64));
let failurei64: IoResult<i64> = deserialize(vec![1u8, 2, 3, 4, 5, 6, 7]); let failurei64: io::Result<i64> = deserialize(vec![1u8, 2, 3, 4, 5, 6, 7]);
assert!(failurei64.is_err()); assert!(failurei64.is_err());
} }
@ -538,15 +538,15 @@ mod tests {
#[test] #[test]
fn deserialize_checkeddata_test() { fn deserialize_checkeddata_test() {
let cd: IoResult<CheckedData> = deserialize(vec![5u8, 0, 0, 0, 162, 107, 175, 90, 1, 2, 3, 4, 5]); let cd: io::Result<CheckedData> = deserialize(vec![5u8, 0, 0, 0, 162, 107, 175, 90, 1, 2, 3, 4, 5]);
assert_eq!(cd, Ok(CheckedData(vec![1u8, 2, 3, 4, 5]))); assert_eq!(cd, Ok(CheckedData(vec![1u8, 2, 3, 4, 5])));
} }
#[test] #[test]
fn deserialize_option_test() { fn deserialize_option_test() {
let none: IoResult<Option<u8>> = deserialize(vec![0u8]); let none: io::Result<Option<u8>> = deserialize(vec![0u8]);
let good: IoResult<Option<u8>> = deserialize(vec![1u8, 0xFF]); let good: io::Result<Option<u8>> = deserialize(vec![1u8, 0xFF]);
let bad: IoResult<Option<u8>> = deserialize(vec![2u8]); let bad: io::Result<Option<u8>> = deserialize(vec![2u8]);
assert!(bad.is_err()); assert!(bad.is_err());
assert_eq!(none, Ok(None)); assert_eq!(none, Ok(None));
assert_eq!(good, Ok(Some(0xFF))); assert_eq!(good, Ok(Some(0xFF)));
@ -554,8 +554,8 @@ mod tests {
#[test] #[test]
fn deserialize_box_test() { fn deserialize_box_test() {
let zero: IoResult<Box<u8>> = deserialize(vec![0u8]); let zero: io::Result<Box<u8>> = deserialize(vec![0u8]);
let one: IoResult<Box<u8>> = deserialize(vec![1u8]); let one: io::Result<Box<u8>> = deserialize(vec![1u8]);
assert_eq!(zero, Ok(Box::new(0))); assert_eq!(zero, Ok(Box::new(0)));
assert_eq!(one, Ok(Box::new(1))); assert_eq!(one, Ok(Box::new(1)));
} }

View File

@ -25,6 +25,7 @@ use network::constants::Network;
use network::message; use network::message;
use network::message::NetworkMessage::Verack; use network::message::NetworkMessage::Verack;
use network::socket::Socket; use network::socket::Socket;
use util;
/// A message which can be sent on the Bitcoin network /// A message which can be sent on the Bitcoin network
pub trait Listener { pub trait Listener {
@ -35,13 +36,11 @@ pub trait Listener {
/// Return the network this `Listener` is operating on /// Return the network this `Listener` is operating on
fn network(&self) -> Network; fn network(&self) -> Network;
/// Main listen loop /// Main listen loop
fn start(&self) -> io::Result<(Receiver<message::SocketResponse>, Socket)> { fn start(&self) -> Result<(Receiver<message::SocketResponse>, Socket), util::Error> {
// Open socket // Open socket
let mut ret_sock = Socket::new(self.network()); let mut ret_sock = Socket::new(self.network());
match ret_sock.connect(self.peer(), self.port()) { if let Err(e) = ret_sock.connect(self.peer(), self.port()) {
Ok(_) => {}, return Err(util::Error::Detail("listener".to_string(), Box::new(e)));
Err(_) => return Err(io::Error::new(io::ErrorKind::ConnectionFailed,
"Listener connection failed", None))
} }
let mut sock = ret_sock.clone(); let mut sock = ret_sock.clone();

View File

@ -32,7 +32,7 @@ use network::message_blockdata;
use network::encodable::{ConsensusDecodable, ConsensusEncodable}; use network::encodable::{ConsensusDecodable, ConsensusEncodable};
use network::encodable::CheckedData; use network::encodable::CheckedData;
use network::serialize::{serialize, RawDecoder, SimpleEncoder, SimpleDecoder}; use network::serialize::{serialize, RawDecoder, SimpleEncoder, SimpleDecoder};
use util::misc::prepend_err; use util::{self, propagate_err};
/// Serializer for command string /// Serializer for command string
#[derive(PartialEq, Eq, Clone, Debug)] #[derive(PartialEq, Eq, Clone, Debug)]
@ -70,7 +70,7 @@ pub enum SocketResponse {
/// A message was received /// A message was received
MessageReceived(NetworkMessage), MessageReceived(NetworkMessage),
/// An error occured and the socket needs to close /// An error occured and the socket needs to close
ConnectionFailed(io::Error, Sender<()>) ConnectionFailed(util::Error, Sender<()>)
} }
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
@ -156,34 +156,30 @@ impl<S: SimpleEncoder> ConsensusEncodable<S> for RawNetworkMessage {
} }
} }
impl<D: SimpleDecoder<Error=io::Error>> ConsensusDecodable<D> for RawNetworkMessage { // TODO: restriction on D::Error is so that `propagate_err` will work;
fn consensus_decode(d: &mut D) -> io::Result<RawNetworkMessage> { // is there a more generic way to handle this?
impl<D: SimpleDecoder<Error=util::Error>> ConsensusDecodable<D> for RawNetworkMessage {
fn consensus_decode(d: &mut D) -> Result<RawNetworkMessage, D::Error> {
let magic = try!(ConsensusDecodable::consensus_decode(d)); let magic = try!(ConsensusDecodable::consensus_decode(d));
let CommandString(cmd): CommandString= try!(ConsensusDecodable::consensus_decode(d)); let CommandString(cmd): CommandString= try!(ConsensusDecodable::consensus_decode(d));
let CheckedData(raw_payload): CheckedData = try!(ConsensusDecodable::consensus_decode(d)); let CheckedData(raw_payload): CheckedData = try!(ConsensusDecodable::consensus_decode(d));
let mut mem_d = RawDecoder::new(Cursor::new(raw_payload)); let mut mem_d = RawDecoder::new(Cursor::new(raw_payload));
let payload = match cmd.as_slice() { let payload = match cmd.as_slice() {
"version" => NetworkMessage::Version(try!(prepend_err("version", ConsensusDecodable::consensus_decode(&mut mem_d)))), "version" => NetworkMessage::Version(try!(propagate_err("version".to_string(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
"verack" => NetworkMessage::Verack, "verack" => NetworkMessage::Verack,
"addr" => NetworkMessage::Addr(try!(prepend_err("addr", ConsensusDecodable::consensus_decode(&mut mem_d)))), "addr" => NetworkMessage::Addr(try!(propagate_err("addr".to_string(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
"inv" => NetworkMessage::Inv(try!(prepend_err("inv", ConsensusDecodable::consensus_decode(&mut mem_d)))), "inv" => NetworkMessage::Inv(try!(propagate_err("inv".to_string(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
"getdata" => NetworkMessage::GetData(try!(prepend_err("getdata", ConsensusDecodable::consensus_decode(&mut mem_d)))), "getdata" => NetworkMessage::GetData(try!(propagate_err("getdata".to_string(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
"notfound" => NetworkMessage::NotFound(try!(prepend_err("notfound", ConsensusDecodable::consensus_decode(&mut mem_d)))), "notfound" => NetworkMessage::NotFound(try!(propagate_err("notfound".to_string(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
"getblocks" => NetworkMessage::GetBlocks(try!(prepend_err("getblocks", ConsensusDecodable::consensus_decode(&mut mem_d)))), "getblocks" => NetworkMessage::GetBlocks(try!(propagate_err("getblocks".to_string(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
"getheaders" => NetworkMessage::GetHeaders(try!(prepend_err("getheaders", ConsensusDecodable::consensus_decode(&mut mem_d)))), "getheaders" => NetworkMessage::GetHeaders(try!(propagate_err("getheaders".to_string(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
"block" => NetworkMessage::Block(try!(prepend_err("block", ConsensusDecodable::consensus_decode(&mut mem_d)))), "block" => NetworkMessage::Block(try!(propagate_err("block".to_string(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
"headers" => NetworkMessage::Headers(try!(prepend_err("headers", ConsensusDecodable::consensus_decode(&mut mem_d)))), "headers" => NetworkMessage::Headers(try!(propagate_err("headers".to_string(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
"ping" => NetworkMessage::Ping(try!(prepend_err("ping", ConsensusDecodable::consensus_decode(&mut mem_d)))), "ping" => NetworkMessage::Ping(try!(propagate_err("ping".to_string(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
"pong" => NetworkMessage::Ping(try!(prepend_err("pong", ConsensusDecodable::consensus_decode(&mut mem_d)))), "pong" => NetworkMessage::Ping(try!(propagate_err("pong".to_string(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
"tx" => NetworkMessage::Tx(try!(prepend_err("tx", ConsensusDecodable::consensus_decode(&mut mem_d)))), "tx" => NetworkMessage::Tx(try!(propagate_err("tx".to_string(), ConsensusDecodable::consensus_decode(&mut mem_d)))),
cmd => { cmd => return Err(d.error(format!("unrecognized network command `{}`", cmd)))
return Err(io::Error {
kind: io::ErrorKind::OtherError,
desc: "unknown message type",
detail: Some(format!("`{}` not recognized", cmd))
});
}
}; };
Ok(RawNetworkMessage { Ok(RawNetworkMessage {
magic: magic, magic: magic,
@ -194,9 +190,9 @@ impl<D: SimpleDecoder<Error=io::Error>> ConsensusDecodable<D> for RawNetworkMess
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::{RawNetworkMessage, CommandString, Verack, Ping}; use super::{RawNetworkMessage, NetworkMessage, CommandString};
use std::io::io::Result; use std::io::Result;
use network::serialize::{deserialize, serialize}; use network::serialize::{deserialize, serialize};
@ -218,7 +214,7 @@ mod test {
#[test] #[test]
fn serialize_verack_test() { fn serialize_verack_test() {
assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: Verack }), assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::Verack }),
Ok(vec![0xf9, 0xbe, 0xb4, 0xd9, 0x76, 0x65, 0x72, 0x61, Ok(vec![0xf9, 0xbe, 0xb4, 0xd9, 0x76, 0x65, 0x72, 0x61,
0x63, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2])); 0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]));
@ -226,7 +222,7 @@ mod test {
#[test] #[test]
fn serialize_ping_test() { fn serialize_ping_test() {
assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: Ping(100) }), assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::Ping(100) }),
Ok(vec![0xf9, 0xbe, 0xb4, 0xd9, 0x70, 0x69, 0x6e, 0x67, Ok(vec![0xf9, 0xbe, 0xb4, 0xd9, 0x70, 0x69, 0x6e, 0x67,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x24, 0x67, 0xf1, 0x1d, 0x08, 0x00, 0x00, 0x00, 0x24, 0x67, 0xf1, 0x1d,

View File

@ -130,7 +130,7 @@ impl<D: SimpleDecoder> ConsensusDecodable<D> for Inventory {
mod tests { mod tests {
use super::{GetHeadersMessage, GetBlocksMessage}; use super::{GetHeadersMessage, GetBlocksMessage};
use std::io::IoResult; use std::io;
use serialize::hex::FromHex; use serialize::hex::FromHex;
use network::serialize::{deserialize, serialize}; use network::serialize::{deserialize, serialize};
@ -141,7 +141,7 @@ mod tests {
let from_sat = "72110100014a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b0000000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap(); let from_sat = "72110100014a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b0000000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap();
let genhash = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".from_hex().unwrap(); let genhash = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".from_hex().unwrap();
let decode: IoResult<GetBlocksMessage> = deserialize(from_sat.clone()); let decode: io::Result<GetBlocksMessage> = deserialize(from_sat.clone());
assert!(decode.is_ok()); assert!(decode.is_ok());
let real_decode = decode.unwrap(); let real_decode = decode.unwrap();
assert_eq!(real_decode.version, 70002); assert_eq!(real_decode.version, 70002);
@ -157,7 +157,7 @@ mod tests {
let from_sat = "72110100014a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b0000000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap(); let from_sat = "72110100014a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b0000000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap();
let genhash = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".from_hex().unwrap(); let genhash = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".from_hex().unwrap();
let decode: IoResult<GetHeadersMessage> = deserialize(from_sat.clone()); let decode: io::Result<GetHeadersMessage> = deserialize(from_sat.clone());
assert!(decode.is_ok()); assert!(decode.is_ok());
let real_decode = decode.unwrap(); let real_decode = decode.unwrap();
assert_eq!(real_decode.version, 70002); assert_eq!(real_decode.version, 70002);

View File

@ -23,6 +23,7 @@ use std::io;
use network::constants; use network::constants;
use network::address::Address; use network::address::Address;
use network::socket::Socket; use network::socket::Socket;
use util;
/// Some simple messages /// Some simple messages
@ -54,24 +55,16 @@ pub struct VersionMessage {
impl VersionMessage { impl VersionMessage {
// TODO: we have fixed services and relay to 0 // TODO: we have fixed services and relay to 0
/// Constructs a new `version` message /// Constructs a new `version` message
pub fn new(timestamp: i64, mut socket: Socket, nonce: u64, start_height: i32) -> io::Result<VersionMessage> { pub fn new(timestamp: i64, mut socket: Socket, nonce: u64, start_height: i32) -> Result<VersionMessage, util::Error> {
let recv_addr = socket.receiver_address(); let recv_addr = try!(socket.receiver_address());
let send_addr = socket.sender_address(); let send_addr = try!(socket.sender_address());
// If we are not connected, we might not be able to get these address.s
match recv_addr {
Err(e) => { return Err(e); }
_ => {}
}
match send_addr {
Err(e) => { return Err(e); }
_ => {}
}
Ok(VersionMessage { Ok(VersionMessage {
version: constants::PROTOCOL_VERSION, version: constants::PROTOCOL_VERSION,
services: socket.services, services: socket.services,
timestamp: timestamp, timestamp: timestamp,
receiver: recv_addr.unwrap(), receiver: recv_addr,
sender: send_addr.unwrap(), sender: send_addr,
nonce: nonce, nonce: nonce,
user_agent: socket.user_agent, user_agent: socket.user_agent,
start_height: start_height, start_height: start_height,

View File

@ -21,10 +21,12 @@
use collections::Vec; use collections::Vec;
use std::io::{self, Cursor, Read, Write}; use std::io::{self, Cursor, Read, Write};
use byteorder::{LittleEndian, WriteBytesExt, ReadBytesExt};
use serialize::hex::ToHex; use serialize::hex::ToHex;
use network::encodable::{ConsensusDecodable, ConsensusEncodable}; use network::encodable::{ConsensusDecodable, ConsensusEncodable};
use util::hash::Sha256dHash; use util::hash::Sha256dHash;
use util;
/// Objects which are referred to by hash /// Objects which are referred to by hash
pub trait BitcoinHash { pub trait BitcoinHash {
@ -33,26 +35,33 @@ pub trait BitcoinHash {
} }
impl BitcoinHash for Vec<u8> { impl BitcoinHash for Vec<u8> {
#[inline]
fn bitcoin_hash(&self) -> Sha256dHash { fn bitcoin_hash(&self) -> Sha256dHash {
Sha256dHash::from_data(self.as_slice()) Sha256dHash::from_data(&self[..])
} }
} }
/// Encode an object into a vector /// Encode an object into a vector
pub fn serialize<T: ConsensusEncodable<RawEncoder<Cursor<Vec<u8>>>>>(obj: &T) -> io::Result<Vec<u8>> { pub fn serialize<T>(data: &T) -> Result<Vec<u8>, util::Error>
where T: ConsensusEncodable<RawEncoder<Cursor<Vec<u8>>>>,
{
let mut encoder = RawEncoder::new(Cursor::new(vec![])); let mut encoder = RawEncoder::new(Cursor::new(vec![]));
try!(obj.consensus_encode(&mut encoder)); try!(data.consensus_encode(&mut encoder));
Ok(encoder.unwrap().unwrap()) Ok(encoder.into_inner().into_inner())
} }
/// Encode an object into a hex-encoded string /// Encode an object into a hex-encoded string
pub fn serialize_hex<T: ConsensusEncodable<RawEncoder<Cursor<Vec<u8>>>>>(obj: &T) -> io::Result<String> { pub fn serialize_hex<T>(data: &T) -> Result<String, util::Error>
let serial = try!(serialize(obj)); where T: ConsensusEncodable<RawEncoder<Cursor<Vec<u8>>>>
Ok(serial.as_slice().to_hex()) {
let serial = try!(serialize(data));
Ok(serial.to_hex())
} }
/// Deserialize an object from a vector /// Deserialize an object from a vector
pub fn deserialize<T: ConsensusDecodable<RawDecoder<Cursor<Vec<u8>>>>>(data: Vec<u8>) -> io::Result<T> { pub fn deserialize<'a, T>(data: &'a [u8]) -> Result<T, util::Error>
where T: ConsensusDecodable<RawDecoder<Cursor<&'a [u8]>>>
{
let mut decoder = RawDecoder::new(Cursor::new(data)); let mut decoder = RawDecoder::new(Cursor::new(data));
ConsensusDecodable::consensus_decode(&mut decoder) ConsensusDecodable::consensus_decode(&mut decoder)
} }
@ -69,26 +78,16 @@ pub struct RawDecoder<R> {
impl<W: Write> RawEncoder<W> { impl<W: Write> RawEncoder<W> {
/// Constructor /// Constructor
pub fn new(writer: W) -> RawEncoder<W> { pub fn new(writer: W) -> RawEncoder<W> { RawEncoder { writer: writer } }
RawEncoder { writer: writer }
}
/// Returns the underlying Writer /// Returns the underlying Writer
pub fn unwrap(self) -> W { pub fn into_inner(self) -> W { self.writer }
self.writer
}
} }
impl<R: Read> RawDecoder<R> { impl<R: Read> RawDecoder<R> {
/// Constructor /// Constructor
pub fn new(reader: R) -> RawDecoder<R> { pub fn new(reader: R) -> RawDecoder<R> { RawDecoder { reader: reader } }
RawDecoder { reader: reader }
}
/// Returns the underlying Reader /// Returns the underlying Reader
pub fn unwrap(self) -> R { pub fn into_inner(self) -> R { self.reader }
self.reader
}
} }
/// A simple Encoder trait /// A simple Encoder trait
@ -143,67 +142,80 @@ pub trait SimpleDecoder {
fn read_bool(&mut self) -> Result<bool, Self::Error>; fn read_bool(&mut self) -> Result<bool, Self::Error>;
/// Signal a decoding error /// Signal a decoding error
fn error(&mut self, err: &str) -> Self::Error; fn error(&mut self, err: String) -> Self::Error;
} }
// TODO: trait reform: impl SimpleEncoder for every Encoder, ditto for Decoder macro_rules! encoder_fn {
($name:ident, $val_type:ty, $writefn:ident) => {
#[inline]
fn $name(&mut self, v: $val_type) -> Result<(), util::Error> {
self.writer.$writefn::<LittleEndian>(v).map_err(util::Error::ByteOrder)
}
}
}
macro_rules! decoder_fn {
($name:ident, $val_type:ty, $readfn:ident) => {
#[inline]
fn $name(&mut self) -> Result<$val_type, util::Error> {
self.reader.$readfn::<LittleEndian>().map_err(util::Error::ByteOrder)
}
}
}
impl<W: Write> SimpleEncoder for RawEncoder<W> { impl<W: Write> SimpleEncoder for RawEncoder<W> {
type Error = io::Error; type Error = util::Error;
encoder_fn!(emit_u64, u64, write_u64);
encoder_fn!(emit_u32, u32, write_u32);
encoder_fn!(emit_u16, u16, write_u16);
encoder_fn!(emit_i64, i64, write_i64);
encoder_fn!(emit_i32, i32, write_i32);
encoder_fn!(emit_i16, i16, write_i16);
#[inline] #[inline]
fn emit_u64(&mut self, v: u64) -> io::Result<()> { self.writer.write_le_u64(v) } fn emit_i8(&mut self, v: i8) -> Result<(), util::Error> {
self.writer.write_i8(v).map_err(util::Error::ByteOrder)
}
#[inline] #[inline]
fn emit_u32(&mut self, v: u32) -> io::Result<()> { self.writer.write_le_u32(v) } fn emit_u8(&mut self, v: u8) -> Result<(), util::Error> {
self.writer.write_u8(v).map_err(util::Error::ByteOrder)
}
#[inline] #[inline]
fn emit_u16(&mut self, v: u16) -> io::Result<()> { self.writer.write_le_u16(v) } fn emit_bool(&mut self, v: bool) -> Result<(), util::Error> {
#[inline] self.writer.write_i8(if v {1} else {0}).map_err(util::Error::ByteOrder)
fn emit_u8(&mut self, v: u8) -> io::Result<()> { self.writer.write_u8(v) } }
#[inline]
fn emit_i64(&mut self, v: i64) -> io::Result<()> { self.writer.write_le_i64(v) }
#[inline]
fn emit_i32(&mut self, v: i32) -> io::Result<()> { self.writer.write_le_i32(v) }
#[inline]
fn emit_i16(&mut self, v: i16) -> io::Result<()> { self.writer.write_le_i16(v) }
#[inline]
fn emit_i8(&mut self, v: i8) -> io::Result<()> { self.writer.write_i8(v) }
#[inline]
fn emit_bool(&mut self, v: bool) -> io::Result<()> { self.writer.write_i8(if v {1} else {0}) }
} }
impl<R: Read> SimpleDecoder for RawDecoder<R> { impl<R: Read> SimpleDecoder for RawDecoder<R> {
type Error = io::Error; type Error = util::Error;
decoder_fn!(read_u64, u64, read_u64);
decoder_fn!(read_u32, u32, read_u32);
decoder_fn!(read_u16, u16, read_u16);
decoder_fn!(read_i64, i64, read_i64);
decoder_fn!(read_i32, i32, read_i32);
decoder_fn!(read_i16, i16, read_i16);
#[inline] #[inline]
fn read_u64(&mut self) -> io::Result<u64> { self.reader.read_le_u64() } fn read_u8(&mut self) -> Result<u8, util::Error> {
#[inline] self.reader.read_u8().map_err(util::Error::ByteOrder)
fn read_u32(&mut self) -> io::Result<u32> { self.reader.read_le_u32() }
#[inline]
fn read_u16(&mut self) -> io::Result<u16> { self.reader.read_le_u16() }
#[inline]
fn read_u8(&mut self) -> io::Result<u8> { self.reader.read_u8() }
#[inline]
fn read_i64(&mut self) -> io::Result<i64> { self.reader.read_le_i64() }
#[inline]
fn read_i32(&mut self) -> io::Result<i32> { self.reader.read_le_i32() }
#[inline]
fn read_i16(&mut self) -> io::Result<i16> { self.reader.read_le_i16() }
#[inline]
fn read_i8(&mut self) -> io::Result<i8> { self.reader.read_i8() }
#[inline]
fn read_bool(&mut self) -> io::Result<bool> { self.reader.read_u8().map(|res| res != 0) }
#[inline]
fn error(&mut self, err: &str) -> io::Error {
io::Error {
kind: io::ErrorKind::OtherError,
desc: "parse error",
detail: Some(err.to_string())
} }
#[inline]
fn read_i8(&mut self) -> Result<i8, util::Error> {
self.reader.read_i8().map_err(util::Error::ByteOrder)
}
#[inline]
fn read_bool(&mut self) -> Result<bool, util::Error> {
match self.reader.read_i8() {
Ok(bit) => Ok(bit != 0),
Err(e) => Err(util::Error::ByteOrder(e))
}
}
#[inline]
fn error(&mut self, err: String) -> util::Error {
util::Error::Detail(err, Box::new(util::Error::ParseFailed))
} }
} }

View File

@ -19,8 +19,7 @@
use time::now; use time::now;
use rand::{thread_rng, Rng}; use rand::{thread_rng, Rng};
use std::io::Cursor; use std::io::{self, Cursor, Write};
use std::io::{Error, Result, ErrorKind};
use std::net::{ip, tcp}; use std::net::{ip, tcp};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
@ -31,7 +30,7 @@ use network::message::{RawNetworkMessage, NetworkMessage};
use network::message::NetworkMessage::Version; use network::message::NetworkMessage::Version;
use network::message_network::VersionMessage; use network::message_network::VersionMessage;
use network::serialize::{RawEncoder, RawDecoder}; use network::serialize::{RawEncoder, RawDecoder};
use util::misc::prepend_err; use util::{self, propagate_err};
/// Format an IP address in the 16-byte bitcoin protocol serialization /// Format an IP address in the 16-byte bitcoin protocol serialization
fn ipaddr_to_bitcoin_addr(ipaddr: &ip::IpAddr) -> [u16; 8] { fn ipaddr_to_bitcoin_addr(ipaddr: &ip::IpAddr) -> [u16; 8] {
@ -44,14 +43,8 @@ fn ipaddr_to_bitcoin_addr(ipaddr: &ip::IpAddr) -> [u16; 8] {
/// A network socket along with information about the peer /// A network socket along with information about the peer
#[derive(Clone)] #[derive(Clone)]
pub struct Socket { pub struct Socket {
/// The underlying socket, which is only used directly to (a) get /// The underlying TCP socket
/// information about the socket, and (b) to close down the socket, socket: Arc<Mutex<Option<tcp::TcpStream>>>,
/// quickly cancelling any read/writes and unlocking the Mutexes.
socket: Option<tcp::TcpStream>,
/// The underlying network data stream read buffer
buffered_reader: Arc<Mutex<Option<tcp::TcpStream>>>,
/// The underlying network data stream write buffer
buffered_writer: Arc<Mutex<Option<tcp::TcpStream>>>,
/// Services supported by us /// Services supported by us
pub services: u64, pub services: u64,
/// Our user agent /// Our user agent
@ -68,9 +61,7 @@ impl Socket {
pub fn new(network: constants::Network) -> Socket { pub fn new(network: constants::Network) -> Socket {
let mut rng = thread_rng(); let mut rng = thread_rng();
Socket { Socket {
socket: None, socket: Arc::new(Mutex::new(None)),
buffered_reader: Arc::new(Mutex::new(None)),
buffered_writer: Arc::new(Mutex::new(None)),
services: 0, services: 0,
version_nonce: rng.gen(), version_nonce: rng.gen(),
user_agent: String::from_str(constants::USER_AGENT), user_agent: String::from_str(constants::USER_AGENT),
@ -78,84 +69,85 @@ impl Socket {
} }
} }
/// Connect to the peer /// (Re)connect to the peer
pub fn connect(&mut self, host: &str, port: u16) -> Result<()> { pub fn connect(&mut self, host: &str, port: u16) -> Result<(), util::Error> {
// Boot off any lingering readers or writers // Entirely replace the Mutex, in case it was poisoned;
if self.socket.is_some() { // this will also drop any preexisting socket that might be open
let _ = self.socket.as_mut().unwrap().close_read(); match tcp::TcpStream::connect((host, port)) {
let _ = self.socket.as_mut().unwrap().close_write();
}
// These locks should just pop open now
let mut reader_lock = self.buffered_reader.lock();
let mut writer_lock = self.buffered_writer.lock();
match tcp::TcpStream::connect(host, port) {
Ok(s) => { Ok(s) => {
*reader_lock = Some(s.clone()); self.socket = Arc::new(Mutex::new(Some(s)));
*writer_lock = Some(s.clone());
self.socket = Some(s);
Ok(()) Ok(())
} }
Err(e) => Err(e) Err(e) => {
self.socket = Arc::new(Mutex::new(None));
Err(util::Error::Io(e))
}
}
}
fn socket(&mut self) -> Result<&mut tcp::TcpStream, util::Error> {
let mut sock_lock = self.socket.lock();
match sock_lock {
Err(_) => {
let io_err = io::Error::new(io::ErrorKind::NotConnected,
"socket: socket mutex was poisoned");
Err(util::Error::Io(io_err))
}
Ok(guard) => {
match *guard {
Some(ref mut sock) => Ok(sock),
None => {
let io_err = io::Error::new(io::ErrorKind::NotConnected,
"socket: not connected to peer");
Err(util::Error::Io(io_err))
}
}
}
} }
} }
/// Peer address /// Peer address
pub fn receiver_address(&mut self) -> Result<Address> { pub fn receiver_address(&mut self) -> Result<Address, util::Error> {
match self.socket { let sock = try!(self.socket());
Some(ref mut s) => match s.peer_name() { match sock.peer_addr() {
Ok(addr) => { Ok(addr) => {
Ok(Address { Ok(Address {
services: self.services, services: self.services,
address: ipaddr_to_bitcoin_addr(&addr.ip), address: ipaddr_to_bitcoin_addr(&addr.ip()),
port: addr.port port: addr.port()
}) })
}
Err(e) => Err(e)
}, },
None => Err(Error::new(ErrorKind::NotConnected, Err(e) => Err(util::Error::Io(e))
"receiver_address: not connected to peer", None))
} }
} }
/// Our own address /// Our own address
pub fn sender_address(&mut self) -> Result<Address> { pub fn sender_address(&mut self) -> Result<Address, util::Error> {
match self.socket { let sock = try!(self.socket());
Some(ref mut s) => match s.socket_name() { match sock.local_addr() {
Ok(addr) => { Ok(addr) => {
Ok(Address { Ok(Address {
services: self.services, services: self.services,
address: ipaddr_to_bitcoin_addr(&addr.ip), address: ipaddr_to_bitcoin_addr(&addr.ip()),
port: addr.port port: addr.port()
}) })
}
Err(e) => Err(e)
}, },
None => Err(Error::new(ErrorKind::NotConnected, Err(e) => Err(util::Error::Io(e))
"sender_address: not connected to peer", None))
} }
} }
/// Produce a version message appropriate for this socket /// Produce a version message appropriate for this socket
pub fn version_message(&mut self, start_height: i32) -> Result<NetworkMessage> { pub fn version_message(&mut self, start_height: i32) -> Result<NetworkMessage, util::Error> {
let recv_addr = try!(self.receiver_address());
let send_addr = try!(self.sender_address());
let timestamp = now().to_timespec().sec; let timestamp = now().to_timespec().sec;
let recv_addr = self.receiver_address();
let send_addr = self.sender_address();
// If we are not connected, we might not be able to get these address.s
match recv_addr {
Err(e) => { return Err(e); }
_ => {}
}
match send_addr {
Err(e) => { return Err(e); }
_ => {}
}
Ok(Version(VersionMessage { Ok(Version(VersionMessage {
version: constants::PROTOCOL_VERSION, version: constants::PROTOCOL_VERSION,
services: constants::SERVICES, services: constants::SERVICES,
timestamp: timestamp, timestamp: timestamp,
receiver: recv_addr.unwrap(), receiver: recv_addr,
sender: send_addr.unwrap(), sender: send_addr,
nonce: self.version_nonce, nonce: self.version_nonce,
user_agent: self.user_agent.clone(), user_agent: self.user_agent.clone(),
start_height: start_height, start_height: start_height,
@ -164,45 +156,31 @@ impl Socket {
} }
/// Send a general message across the line /// Send a general message across the line
pub fn send_message(&mut self, payload: NetworkMessage) -> Result<()> { pub fn send_message(&mut self, payload: NetworkMessage) -> Result<(), util::Error> {
let mut writer_lock = self.buffered_writer.lock(); let sock = try!(self.socket());
match *writer_lock.deref_mut() {
None => Err(Error::new(ErrorKind::NotConnected,
"send_message: not connected to peer", None)),
Some(ref mut writer) => {
let message = RawNetworkMessage { magic: self.magic, payload: payload }; let message = RawNetworkMessage { magic: self.magic, payload: payload };
try!(message.consensus_encode(&mut RawEncoder::new(writer.by_ref()))); try!(message.consensus_encode(&mut RawEncoder::new(sock)));
writer.flush() sock.flush().map_err(util::Error::Io)
}
}
} }
/// Receive the next message from the peer, decoding the network header /// Receive the next message from the peer, decoding the network header
/// and verifying its correctness. Returns the undecoded payload. /// and verifying its correctness. Returns the undecoded payload.
pub fn receive_message(&mut self) -> Result<NetworkMessage> { pub fn receive_message(&mut self) -> Result<NetworkMessage, util::Error> {
let mut reader_lock = self.buffered_reader.lock(); let sock = try!(self.socket());
match *reader_lock.deref_mut() {
None => Err(Error::new(ErrorKind::NotConnected,
"receive_message: not connected to peer", None)),
Some(ref mut buf) => {
// We need a new scope since the closure in here borrows read_err, // We need a new scope since the closure in here borrows read_err,
// and we try to read it afterward. Letting `iter` go out fixes it. // and we try to read it afterward. Letting `iter` go out fixes it.
let mut decoder = RawDecoder::new(buf.by_ref()); let mut decoder = RawDecoder::new(sock);
let decode: Result<RawNetworkMessage> = ConsensusDecodable::consensus_decode(&mut decoder); let decode: Result<RawNetworkMessage, _> = ConsensusDecodable::consensus_decode(&mut decoder);
match decode { match decode {
// Check for parse errors... // Check for parse errors...
Err(e) => { Err(e) => {
prepend_err("network_decode", Err(e)) propagate_err("receive_message".to_string(), Err(e))
}, },
Ok(ret) => { Ok(ret) => {
// Then for magic (this should come before parse error, but we can't // Then for magic (this should come before parse error, but we can't
// get to it if the deserialization failed). TODO restructure this // get to it if the deserialization failed). TODO restructure this
if ret.magic != self.magic { if ret.magic != self.magic {
Err(Error { Err(util::Error::BadNetworkMagic(self.magic, ret.magic))
kind: ErrorKind::OtherError,
desc: "bad magic",
detail: Some(format!("got magic {:x}, expected {:x}", ret.magic, self.magic)),
})
} else { } else {
Ok(ret.payload) Ok(ret.payload)
} }
@ -210,7 +188,4 @@ impl Socket {
} }
} }
} }
}
}

View File

@ -14,7 +14,7 @@
//! # Base58 encoder and decoder //! # Base58 encoder and decoder
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};
use std::str; use std::str;
@ -102,7 +102,7 @@ pub trait FromBase58 {
return Err(Error::TooShort(ret.len())); return Err(Error::TooShort(ret.len()));
} }
let ck_start = ret.len() - 4; let ck_start = ret.len() - 4;
let expected = Sha256dHash::from_data(ret.slice_to(ck_start)).into_le().low_u32(); let expected = Sha256dHash::from_data(&ret[..ck_start]).into_le().low_u32();
let actual = LittleEndian::read_u32(&ret[ck_start..(ck_start + 4)]); let actual = LittleEndian::read_u32(&ret[ck_start..(ck_start + 4)]);
if expected != actual { if expected != actual {
return Err(Error::BadChecksum(expected, actual)); return Err(Error::BadChecksum(expected, actual));
@ -116,7 +116,7 @@ pub trait FromBase58 {
/// Directly encode a slice as base58 /// Directly encode a slice as base58
pub fn base58_encode_slice(data: &[u8]) -> String { pub fn base58_encode_slice(data: &[u8]) -> String {
// 7/5 is just over log_58(256) // 7/5 is just over log_58(256)
let mut scratch = Vec::from_elem(1 + data.len() * 7 / 5, 0u8); let mut scratch = vec![0u8; 1 + data.len() * 7 / 5];
// Build in base 58 // Build in base 58
for &d256 in data.base58_layout().iter() { for &d256 in data.base58_layout().iter() {
// Compute "X = X * 256 + next_digit" in base 58 // Compute "X = X * 256 + next_digit" in base 58
@ -132,9 +132,9 @@ pub fn base58_encode_slice(data: &[u8]) -> String {
// Unsafely translate the bytes to a utf8 string // Unsafely translate the bytes to a utf8 string
unsafe { unsafe {
// Copy leading zeroes directly // Copy leading zeroes directly
let mut ret = str::from_utf8(data.iter().take_while(|&&x| x == 0) let mut ret: Vec<u8> = str::from_utf8(data.iter().take_while(|&&x| x == 0)
.map(|_| BASE58_CHARS[0]) .map(|_| BASE58_CHARS[0])
.collect()); .collect()).unwrap();
// Copy rest of string // Copy rest of string
ret.as_mut_vec().extend(scratch.into_iter().skip_while(|&x| x == 0) ret.as_mut_vec().extend(scratch.into_iter().skip_while(|&x| x == 0)
.map(|x| BASE58_CHARS[x as usize])); .map(|x| BASE58_CHARS[x as usize]));
@ -149,16 +149,16 @@ pub trait ToBase58 {
/// Obtain a string with the base58 encoding of the object /// Obtain a string with the base58 encoding of the object
fn to_base58(&self) -> String { fn to_base58(&self) -> String {
base58_encode_slice(self.base58_layout().as_slice()) base58_encode_slice(&self.base58_layout()[..])
} }
/// Obtain a string with the base58check encoding of the object /// Obtain a string with the base58check encoding of the object
/// (Tack the first 4 256-digits of the object's Bitcoin hash onto the end.) /// (Tack the first 4 256-digits of the object's Bitcoin hash onto the end.)
fn to_base58check(&self) -> String { fn to_base58check(&self) -> String {
let mut data = self.base58_layout(); let mut data = self.base58_layout();
let checksum = Sha256dHash::from_data(data.as_slice()).into_le().low_u32(); let checksum = Sha256dHash::from_data(&data).into_le().low_u32();
data.write_u32::<LittleEndian>(checksum); data.write_u32::<LittleEndian>(checksum);
base58_encode_slice(data.as_slice()) base58_encode_slice(&data)
} }
} }
@ -168,11 +168,6 @@ impl<'a> ToBase58 for &'a [u8] {
fn to_base58(&self) -> String { base58_encode_slice(*self) } fn to_base58(&self) -> String { base58_encode_slice(*self) }
} }
impl ToBase58 for Vec<u8> {
fn base58_layout(&self) -> Vec<u8> { self.clone() }
fn to_base58(&self) -> String { base58_encode_slice(self.as_slice()) }
}
impl FromBase58 for Vec<u8> { impl FromBase58 for Vec<u8> {
fn from_base58_layout(data: Vec<u8>) -> Result<Vec<u8>, Error> { fn from_base58_layout(data: Vec<u8>) -> Result<Vec<u8>, Error> {
Ok(data) Ok(data)

View File

@ -1,38 +0,0 @@
// Rust Bitcoin Library
// Written in 2014 by
// Andrew Poelstra <apoelstra@wpsoftware.net>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//
//! # Error codes
//!
//! Various utility functions
use std::io;
/// A general error code
#[derive(PartialEq, Eq, Debug, Clone)]
pub enum Error {
/// An I/O error
InputOutput(io::Error),
/// An object was attempted to be added twice
DuplicateHash,
/// Some operation was attempted on a block (or blockheader) that doesn't exist
BlockNotFound,
/// An object was added but it does not link into existing history
PrevHashNotFound,
/// The `target` field of a block header did not match the expected difficulty
SpvBadTarget,
/// The header hash is not below the target
SpvBadProofOfWork
}

View File

@ -18,7 +18,7 @@
use std::char::from_digit; use std::char::from_digit;
use std::cmp::min; use std::cmp::min;
use std::default::Default; use std::default::Default;
use std::fmt; use std::fmt::{self, Write};
use std::io::Cursor; use std::io::Cursor;
use std::mem::transmute; use std::mem::transmute;
use std::hash; use std::hash;
@ -65,7 +65,7 @@ impl Ripemd160Hash {
let mut ret = [0; 20]; let mut ret = [0; 20];
let mut rmd = Ripemd160::new(); let mut rmd = Ripemd160::new();
rmd.input(data); rmd.input(data);
rmd.result(ret.as_mut_slice()); rmd.result(&mut ret);
Ripemd160Hash(ret) Ripemd160Hash(ret)
} }
} }
@ -83,10 +83,10 @@ impl Sha256dHash {
let Sha256dHash(mut ret): Sha256dHash = Default::default(); let Sha256dHash(mut ret): Sha256dHash = Default::default();
let mut sha2 = Sha256::new(); let mut sha2 = Sha256::new();
sha2.input(data); sha2.input(data);
sha2.result(ret.as_mut_slice()); sha2.result(&mut ret);
sha2.reset(); sha2.reset();
sha2.input(ret.as_slice()); sha2.input(&ret);
sha2.result(ret.as_mut_slice()); sha2.result(&mut ret);
Sha256dHash(ret) Sha256dHash(ret)
} }
@ -95,7 +95,7 @@ impl Sha256dHash {
pub fn into_le(self) -> Uint256 { pub fn into_le(self) -> Uint256 {
let Sha256dHash(data) = self; let Sha256dHash(data) = self;
let mut ret: [u64; 4] = unsafe { transmute(data) }; let mut ret: [u64; 4] = unsafe { transmute(data) };
for x in ret.as_mut_slice().iter_mut() { *x = x.to_le(); } for x in (&mut ret).iter_mut() { *x = x.to_le(); }
Uint256(ret) Uint256(ret)
} }
@ -105,7 +105,7 @@ impl Sha256dHash {
let Sha256dHash(mut data) = self; let Sha256dHash(mut data) = self;
data.reverse(); data.reverse();
let mut ret: [u64; 4] = unsafe { transmute(data) }; let mut ret: [u64; 4] = unsafe { transmute(data) };
for x in ret.iter_mut() { *x = x.to_be(); } for x in (&mut ret).iter_mut() { *x = x.to_be(); }
Uint256(ret) Uint256(ret)
} }
@ -138,8 +138,8 @@ impl Sha256dHash {
let &Sha256dHash(data) = self; let &Sha256dHash(data) = self;
let mut ret = String::with_capacity(64); let mut ret = String::with_capacity(64);
for i in 0..32 { for i in 0..32 {
ret.push_char(from_digit((data[i] / 0x10) as usize, 16).unwrap()); ret.push(from_digit((data[i] / 0x10) as u32, 16).unwrap());
ret.push_char(from_digit((data[i] & 0x0f) as usize, 16).unwrap()); ret.push(from_digit((data[i] & 0x0f) as u32, 16).unwrap());
} }
ret ret
} }
@ -149,8 +149,8 @@ impl Sha256dHash {
let &Sha256dHash(data) = self; let &Sha256dHash(data) = self;
let mut ret = String::with_capacity(64); let mut ret = String::with_capacity(64);
for i in (0..32).rev() { for i in (0..32).rev() {
ret.push_char(from_digit((data[i] / 0x10) as usize, 16).unwrap()); ret.push(from_digit((data[i] / 0x10) as u32, 16).unwrap());
ret.push_char(from_digit((data[i] & 0x0f) as usize, 16).unwrap()); ret.push(from_digit((data[i] & 0x0f) as u32, 16).unwrap());
} }
ret ret
} }
@ -191,7 +191,7 @@ impl serde::Deserialize for Sha256dHash {
if hex_str.len() != 64 { if hex_str.len() != 64 {
return Err(serde::de::Error::syntax_error()); return Err(serde::de::Error::syntax_error());
} }
let raw_str = try!(hex_str.as_slice().from_hex() let raw_str = try!(hex_str.from_hex()
.map_err(|_| serde::de::Error::syntax_error())); .map_err(|_| serde::de::Error::syntax_error()));
let mut ret = [0u8; 32]; let mut ret = [0u8; 32];
for i in 0..32 { for i in 0..32 {
@ -215,12 +215,10 @@ impl fmt::LowerHex for Sha256dHash {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let &Sha256dHash(data) = self; let &Sha256dHash(data) = self;
let mut rv = [0; 64]; let mut rv = [0; 64];
let mut hex = data.iter().rev().map(|n| *n).enumerate(); for ch in data.iter().rev() {
for (i, ch) in hex { try!(write!(f, "{:02x}", ch));
rv[2*i] = from_digit(ch as usize / 16, 16).unwrap() as u8;
rv[2*i + 1] = from_digit(ch as usize % 16, 16).unwrap() as u8;
} }
f.write(rv.as_slice()) Ok(())
} }
} }
@ -249,7 +247,7 @@ impl<'a, T: BitcoinHash> MerkleRoot for &'a [T] {
let mut encoder = RawEncoder::new(Cursor::new(vec![])); let mut encoder = RawEncoder::new(Cursor::new(vec![]));
data[idx1].consensus_encode(&mut encoder).unwrap(); data[idx1].consensus_encode(&mut encoder).unwrap();
data[idx2].consensus_encode(&mut encoder).unwrap(); data[idx2].consensus_encode(&mut encoder).unwrap();
next.push(encoder.unwrap().unwrap().bitcoin_hash()); next.push(encoder.unwrap().into_inner().bitcoin_hash());
} }
merkle_root(next) merkle_root(next)
} }
@ -259,7 +257,7 @@ impl<'a, T: BitcoinHash> MerkleRoot for &'a [T] {
impl <T: BitcoinHash> MerkleRoot for Vec<T> { impl <T: BitcoinHash> MerkleRoot for Vec<T> {
fn merkle_root(&self) -> Sha256dHash { fn merkle_root(&self) -> Sha256dHash {
self.as_slice().merkle_root() (&self[..]).merkle_root()
} }
} }
@ -303,7 +301,7 @@ mod tests {
assert!(hash.encode(&mut encoder).is_ok()); assert!(hash.encode(&mut encoder).is_ok());
} }
let res = writer.unwrap(); let res = writer.unwrap();
assert_eq!(res.as_slice(), assert_eq!(&res.as_slice(),
"\"56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d\"".as_bytes()); "\"56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d\"".as_bytes());
assert_eq!(json::decode(from_utf8(res.as_slice()).unwrap()), Ok(hash)); assert_eq!(json::decode(from_utf8(res.as_slice()).unwrap()), Ok(hash));
} }

View File

@ -16,61 +16,47 @@
//! //!
//! Various utility functions //! Various utility functions
use std::io::{Error, Result, ErrorKind};
use blockdata::opcodes; use blockdata::opcodes;
use util::Error;
use util::iter::Pairable; use util::iter::Pairable;
/// Convert a hexadecimal-encoded string to its corresponding bytes /// Convert a hexadecimal-encoded string to its corresponding bytes
pub fn hex_bytes(s: &str) -> Result<Vec<u8>> { pub fn hex_bytes(s: &str) -> Result<Vec<u8>, Error> {
let mut v = vec![]; let mut v = vec![];
let mut iter = s.chars().pair(); let mut iter = s.chars().pair();
// Do the parsing // Do the parsing
try!(iter.fold(Ok(()), |e, (f, s)| try!(iter.fold(Ok(()), |e, (f, s)|
if e.is_err() { return e; } if e.is_err() { e }
else { else {
match (f.to_digit(16), s.to_digit(16)) { match (f.to_digit(16), s.to_digit(16)) {
(None, _) => return Err(Error { (None, _) => Err(Error::Detail(
kind: ErrorKind::InvalidInput, format!("expected hex, got {:}", f),
desc: "invalid hex character", Box::new(Error::ParseFailed)
detail: Some(format!("expected hex, got {:}", f)) )),
}), (_, None) => Err(Error::Detail(
(_, None) => return Err(Error { format!("expected hex, got {:}", s),
kind: ErrorKind::InvalidInput, Box::new(Error::ParseFailed)
desc: "invalid hex character", )),
detail: Some(format!("expected hex, got {:}", s))
}),
(Some(f), Some(s)) => { v.push((f * 0x10 + s) as u8); Ok(()) } (Some(f), Some(s)) => { v.push((f * 0x10 + s) as u8); Ok(()) }
} }
} }
)); ));
// Check that there was no remainder // Check that there was no remainder
match iter.remainder() { match iter.remainder() {
Some(_) => Err(Error { Some(_) => Err(Error::Detail(
kind: ErrorKind::InvalidInput, format!("hexstring of odd length"),
desc: "hexstring of odd length", Box::new(Error::ParseFailed)
detail: None )),
}),
None => Ok(v) None => Ok(v)
} }
} }
/// Prepend the detail of an IoResult's error with some text to get poor man's backtracing
pub fn prepend_err<T>(s: &str, res: Result<T>) -> Result<T> {
res.map_err(|err| {
Error {
kind: err.kind,
desc: err.desc,
detail: Some(format!("{}: {}", s, match err.detail { Some(s) => s, None => String::new() }))
}
})
}
/// Dump an error message to the screen /// Dump an error message to the screen
pub fn consume_err<T>(s: &str, res: Result<T>) { /// TODO all uses of this should be replaced with some sort of logging infrastructure
pub fn consume_err<T>(s: &str, res: Result<T, Error>) {
match res { match res {
Ok(_) => {}, Ok(_) => {},
Err(e) => { println!("{}: {}", s, e); } Err(e) => { println!("{}: {:?}", s, e); }
}; };
} }
@ -86,8 +72,8 @@ pub fn script_find_and_remove(haystack: &mut Vec<u8>, needle: &[u8]) -> usize {
let mut i = 0; let mut i = 0;
while i <= top { while i <= top {
if haystack.slice(i, i + needle.len()) == needle { if &haystack[i..(i + needle.len())] == needle {
let v = haystack.as_mut_slice(); let v = &mut haystack;
for j in i..top { for j in i..top {
v.swap(j + needle.len(), j); v.swap(j + needle.len(), j);
} }
@ -158,7 +144,7 @@ mod tests {
#[test] #[test]
fn test_hex_bytes() { fn test_hex_bytes() {
assert_eq!(hex_bytes("abcd").unwrap().as_slice(), [171u8, 205].as_slice()); assert_eq!(&hex_bytes("abcd").unwrap(), &[171u8, 205]);
assert!(hex_bytes("abcde").is_err()); assert!(hex_bytes("abcde").is_err());
assert!(hex_bytes("aBcDeF").is_ok()); assert!(hex_bytes("aBcDeF").is_ok());
assert!(hex_bytes("aBcD4eFL").is_err()); assert!(hex_bytes("aBcD4eFL").is_err());

View File

@ -17,13 +17,15 @@
//! Functions needed by all parts of the Bitcoin library //! Functions needed by all parts of the Bitcoin library
pub mod base58; pub mod base58;
pub mod error;
pub mod hash; pub mod hash;
pub mod iter; pub mod iter;
pub mod misc; pub mod misc;
pub mod patricia_tree; pub mod patricia_tree;
pub mod uint; pub mod uint;
use byteorder;
use std::io;
/// A trait which allows numbers to act as fixed-size bit arrays /// A trait which allows numbers to act as fixed-size bit arrays
pub trait BitArray { pub trait BitArray {
/// Is bit set? /// Is bit set?
@ -39,3 +41,37 @@ pub trait BitArray {
fn trailing_zeros(&self) -> usize; fn trailing_zeros(&self) -> usize;
} }
/// A general error code
#[derive(Debug)]
pub enum Error {
/// An I/O error
Io(io::Error),
/// Order from the `byteorder` crate
ByteOrder(byteorder::Error),
/// Network magic was not what we expected
BadNetworkMagic(u32, u32),
/// Network message was unrecognized
BadNetworkMessage(String),
/// An object was attempted to be added twice
DuplicateHash,
/// Some operation was attempted on a block (or blockheader) that doesn't exist
BlockNotFound,
/// Parsing error
ParseFailed,
/// An object was added but it does not link into existing history
PrevHashNotFound,
/// The `target` field of a block header did not match the expected difficulty
SpvBadTarget,
/// The header hash is not below the target
SpvBadProofOfWork,
/// Error propagated from subsystem
Detail(String, Box<Error>)
}
display_from_debug!(Error);
/// Prepend the detail of an IoResult's error with some text to get poor man's backtracing
pub fn propagate_err<T>(s: String, res: Result<T, Error>) -> Result<T, Error> {
res.map_err(|err| Error::Detail(s, Box::new(err)))
}

View File

@ -23,7 +23,7 @@
use std::fmt::Debug; use std::fmt::Debug;
use std::marker; use std::marker;
use std::num::{Zero, One}; use std::num::{Zero, One};
use std::{cmp, ops, ptr}; use std::{cmp, fmt, ops, ptr};
use network::encodable::{ConsensusDecodable, ConsensusEncodable}; use network::encodable::{ConsensusDecodable, ConsensusEncodable};
use network::serialize::{SimpleDecoder, SimpleEncoder}; use network::serialize::{SimpleDecoder, SimpleEncoder};
@ -39,7 +39,11 @@ pub struct PatriciaTree<K, V> {
} }
impl<K, V> PatriciaTree<K, V> impl<K, V> PatriciaTree<K, V>
where K: BitArray + cmp::Eq + Zero + One + ops::BitXor<K> + ops::Shl<usize> + ops::Shr<usize> where K: BitArray + cmp::Eq + Zero + One +
ops::BitXor<K, Output=K> +
ops::Add<K, Output=K> +
ops::Shr<usize, Output=K> +
ops::Shl<usize, Output=K>
{ {
/// Constructs a new Patricia tree /// Constructs a new Patricia tree
pub fn new() -> PatriciaTree<K, V> { pub fn new() -> PatriciaTree<K, V> {
@ -217,7 +221,10 @@ impl<K, V> PatriciaTree<K, V>
/// Return value is (deletable, actual return value), where `deletable` is true /// Return value is (deletable, actual return value), where `deletable` is true
/// is true when the entire node can be deleted (i.e. it has no children) /// is true when the entire node can be deleted (i.e. it has no children)
fn recurse<K, V>(tree: &mut PatriciaTree<K, V>, key: &K, key_len: usize) -> (bool, Option<V>) fn recurse<K, V>(tree: &mut PatriciaTree<K, V>, key: &K, key_len: usize) -> (bool, Option<V>)
where K: BitArray + cmp::Eq + Zero + One + ops::Add<K> + ops::Shr<usize> + ops::Shl<usize> where K: BitArray + cmp::Eq + Zero + One +
ops::Add<K, Output=K> +
ops::Shr<usize, Output=K> +
ops::Shl<usize, Output=K>
{ {
// If the search key is shorter than the node prefix, there is no // If the search key is shorter than the node prefix, there is no
// way we can match, so fail. // way we can match, so fail.
@ -275,7 +282,7 @@ impl<K, V> PatriciaTree<K, V>
} }
// Otherwise, do it // Otherwise, do it
let (delete_child, ret) = recurse(&mut **target.as_mut().unwrap(), let (delete_child, ret) = recurse(&mut **target.as_mut().unwrap(),
&key.shr(&(tree.skip_len as usize + 1)), &(*key >> (tree.skip_len as usize + 1)),
key_len - tree.skip_len as usize - 1); key_len - tree.skip_len as usize - 1);
if delete_child { if delete_child {
target.take(); target.take();
@ -355,22 +362,22 @@ impl<K, V> PatriciaTree<K, V>
} }
} }
impl<K:BitArray, V:Debug> PatriciaTree<K, V> { impl<K:BitArray, V:Debug> Debug for PatriciaTree<K, V> {
/// Print the entire tree /// Print the entire tree
pub fn print<'a>(&'a self) { pub fn fmt<'a>(&'a self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fn recurse<'a, K:BitArray, V:Debug>(tree: &'a PatriciaTree<K, V>, depth: usize) { fn recurse<'a, K:BitArray, V:Debug>(tree: &'a PatriciaTree<K, V>, f: &mut fmt::Formatter, depth: usize) -> Result<(), fmt::Error> {
for i in 0..tree.skip_len as usize { for i in 0..tree.skip_len as usize {
print!("{:}", if tree.skip_prefix.bit(i) { 1 } else { 0 }); try!(write!(f, "{:}", if tree.skip_prefix.bit(i) { 1 } else { 0 }));
} }
println!(": {:}", tree.data); try!(writeln!(f, ": {:?}", tree.data));
// left gets no indentation // left gets no indentation
match tree.child_l { match tree.child_l {
Some(ref t) => { Some(ref t) => {
for _ in 0..(depth + tree.skip_len as usize) { for _ in 0..(depth + tree.skip_len as usize) {
print!("-"); try!(write!(f, "-"));
} }
print!("0"); try!(write!(f, "0"));
recurse(&**t, depth + tree.skip_len as usize + 1); try!(recurse(&**t, f, depth + tree.skip_len as usize + 1));
} }
None => { } None => { }
} }
@ -378,15 +385,16 @@ impl<K:BitArray, V:Debug> PatriciaTree<K, V> {
match tree.child_r { match tree.child_r {
Some(ref t) => { Some(ref t) => {
for _ in 0..(depth + tree.skip_len as usize) { for _ in 0..(depth + tree.skip_len as usize) {
print!("_"); try!(write!(f, "_"));
} }
print!("1"); try!(write!(f, "1"));
recurse(&**t, depth + tree.skip_len as usize + 1); try!(recurse(&**t, f, depth + tree.skip_len as usize + 1));
} }
None => { } None => { }
} }
Ok(())
} }
recurse(self, 0); recurse(self, f, 0);
} }
} }
@ -430,7 +438,7 @@ pub struct Items<'tree, K: 'tree, V: 'tree> {
} }
/// Mutable iterator /// Mutable iterator
pub struct MutItems<'tree, K, V> { pub struct MutItems<'tree, K: 'tree, V: 'tree> {
started: bool, started: bool,
node: *mut PatriciaTree<K, V>, node: *mut PatriciaTree<K, V>,
parents: Vec<*mut PatriciaTree<K, V>>, parents: Vec<*mut PatriciaTree<K, V>>,
@ -490,7 +498,7 @@ impl<'a, K, V> Iterator for MutItems<'a, K, V> {
fn borrow_opt<'a, K, V>(opt_ptr: &'a Option<Box<PatriciaTree<K, V>>>) -> *mut PatriciaTree<K, V> { fn borrow_opt<'a, K, V>(opt_ptr: &'a Option<Box<PatriciaTree<K, V>>>) -> *mut PatriciaTree<K, V> {
match *opt_ptr { match *opt_ptr {
Some(ref data) => &**data as *const _ as *mut _, Some(ref data) => &**data as *const _ as *mut _,
None => ptr::null() None => ptr::null_mut()
} }
} }
@ -498,7 +506,7 @@ impl<'a, K, V> Iterator for MutItems<'a, K, V> {
// which will be the root node. // which will be the root node.
if !self.started { if !self.started {
unsafe { unsafe {
if self.node.is_not_null() && (*self.node).data.is_some() { if !self.node.is_null() && (*self.node).data.is_some() {
return (*self.node).data.as_mut(); return (*self.node).data.as_mut();
} }
} }
@ -506,30 +514,30 @@ impl<'a, K, V> Iterator for MutItems<'a, K, V> {
} }
// Find next data-containing node // Find next data-containing node
while self.node.is_not_null() { while !self.node.is_null() {
// Try to go left // Try to go left
let child_l = unsafe { borrow_opt(&(*self.node).child_l) }; let child_l = unsafe { borrow_opt(&(*self.node).child_l) };
if child_l.is_not_null() { if !child_l.is_null() {
self.parents.push(self.node); self.parents.push(self.node);
self.node = child_l; self.node = child_l;
// Try to go right, going back up the tree if necessary // Try to go right, going back up the tree if necessary
} else { } else {
while self.node.is_not_null() { while !self.node.is_null() {
let child_r = unsafe { borrow_opt(&(*self.node).child_r) }; let child_r = unsafe { borrow_opt(&(*self.node).child_r) };
if child_r.is_not_null() { if !child_r.is_null() {
self.node = child_r; self.node = child_r;
break; break;
} }
self.node = self.parents.pop().unwrap_or(ptr::null()); self.node = self.parents.pop().unwrap_or(ptr::null_mut());
} }
} }
// Stop if we've found data. // Stop if we've found data.
if self.node.is_not_null() && unsafe { (*self.node).data.is_some() } { if !self.node.is_null() && unsafe { (*self.node).data.is_some() } {
break; break;
} }
} // end loop } // end loop
// Return data // Return data
if self.node.is_not_null() { if !self.node.is_null() {
unsafe { (*self.node).data.as_mut() } unsafe { (*self.node).data.as_mut() }
} else { } else {
None None
@ -540,7 +548,7 @@ impl<'a, K, V> Iterator for MutItems<'a, K, V> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::prelude::*; use std::prelude::*;
use std::io::IoResult; use std::io;
use std::num::Zero; use std::num::Zero;
use network::serialize::{deserialize, serialize}; use network::serialize::{deserialize, serialize};
@ -698,7 +706,7 @@ mod tests {
// Serialize it // Serialize it
let serialized = serialize(&tree).unwrap(); let serialized = serialize(&tree).unwrap();
// Deserialize it // Deserialize it
let deserialized: IoResult<PatriciaTree<Uint128, u32>> = deserialize(serialized); let deserialized: io::Result<PatriciaTree<Uint128, u32>> = deserialize(serialized);
assert!(deserialized.is_ok()); assert!(deserialized.is_ok());
let new_tree = deserialized.unwrap(); let new_tree = deserialized.unwrap();

View File

@ -46,12 +46,12 @@ macro_rules! construct_uint {
for i in 1..$n_words { for i in 1..$n_words {
if arr[$n_words - i] > 0 { return (0x40 * ($n_words - i + 1)) - arr[$n_words - i].leading_zeros() as usize; } if arr[$n_words - i] > 0 { return (0x40 * ($n_words - i + 1)) - arr[$n_words - i].leading_zeros() as usize; }
} }
0x40 - arr[0].leading_zeros() 0x40 - arr[0].leading_zeros() as usize
} }
/// Multiplication by u32 /// Multiplication by u32
pub fn mul_u32(&self, other: u32) -> $name { pub fn mul_u32(self, other: u32) -> $name {
let &$name(ref arr) = self; let $name(ref arr) = self;
let mut carry = [0u64; $n_words]; let mut carry = [0u64; $n_words];
let mut ret = [0u64; $n_words]; let mut ret = [0u64; $n_words];
for i in 0..$n_words { for i in 0..$n_words {
@ -93,9 +93,9 @@ macro_rules! construct_uint {
impl ::std::ops::Add<$name> for $name { impl ::std::ops::Add<$name> for $name {
type Output = $name; type Output = $name;
fn add(&self, other: &$name) -> $name { fn add(self, other: $name) -> $name {
let &$name(ref me) = self; let $name(ref me) = self;
let &$name(ref you) = other; let $name(ref you) = other;
let mut ret = [0u64; $n_words]; let mut ret = [0u64; $n_words];
let mut carry = [0u64; $n_words]; let mut carry = [0u64; $n_words];
let mut b_carry = false; let mut b_carry = false;
@ -114,16 +114,16 @@ macro_rules! construct_uint {
type Output = $name; type Output = $name;
#[inline] #[inline]
fn sub(&self, other: &$name) -> $name { fn sub(self, other: $name) -> $name {
*self + !*other + One::one() self + !other + One::one()
} }
} }
impl ::std::ops::Mul<$name> for $name { impl ::std::ops::Mul<$name> for $name {
type Output = $name; type Output = $name;
fn mul(&self, other: &$name) -> $name { fn mul(self, other: $name) -> $name {
let mut me = *self; let mut me = self;
// TODO: be more efficient about this // TODO: be more efficient about this
for i in 0..(2 * $n_words) { for i in 0..(2 * $n_words) {
me = me + me.mul_u32((other >> (32 * i)).low_u32()) << (32 * i); me = me + me.mul_u32((other >> (32 * i)).low_u32()) << (32 * i);
@ -135,9 +135,9 @@ macro_rules! construct_uint {
impl ::std::ops::Div<$name> for $name { impl ::std::ops::Div<$name> for $name {
type Output = $name; type Output = $name;
fn div(&self, other: &$name) -> $name { fn div(self, other: $name) -> $name {
let mut sub_copy = *self; let mut sub_copy = self;
let mut shift_copy = *other; let mut shift_copy = other;
let mut ret = [0u64; $n_words]; let mut ret = [0u64; $n_words];
let my_bits = self.bits(); let my_bits = self.bits();
@ -157,7 +157,7 @@ macro_rules! construct_uint {
loop { loop {
if sub_copy >= shift_copy { if sub_copy >= shift_copy {
ret[shift / 64] |= 1 << (shift % 64); ret[shift / 64] |= 1 << (shift % 64);
sub_copy = sub_copy.sub(&shift_copy); sub_copy = sub_copy - shift_copy;
} }
shift_copy = shift_copy >> 1; shift_copy = shift_copy >> 1;
if shift == 0 { break; } if shift == 0 { break; }
@ -177,7 +177,7 @@ macro_rules! construct_uint {
#[inline] #[inline]
fn bit_slice(&self, start: usize, end: usize) -> $name { fn bit_slice(&self, start: usize, end: usize) -> $name {
(self >> start).mask(end - start) (*self >> start).mask(end - start)
} }
#[inline] #[inline]
@ -199,9 +199,9 @@ macro_rules! construct_uint {
fn trailing_zeros(&self) -> usize { fn trailing_zeros(&self) -> usize {
let &$name(ref arr) = self; let &$name(ref arr) = self;
for i in 0..($n_words - 1) { for i in 0..($n_words - 1) {
if arr[i] > 0 { return (0x40 * i) + arr[i].trailing_zeros(); } if arr[i] > 0 { return (0x40 * i) + arr[i].trailing_zeros() as usize; }
} }
(0x40 * ($n_words - 1)) + arr[3].trailing_zeros() (0x40 * ($n_words - 1)) + arr[3].trailing_zeros() as usize
} }
} }
@ -209,9 +209,9 @@ macro_rules! construct_uint {
type Output = $name; type Output = $name;
#[inline] #[inline]
fn bitand(&self, other: &$name) -> $name { fn bitand(self, other: $name) -> $name {
let &$name(ref arr1) = self; let $name(ref arr1) = self;
let &$name(ref arr2) = other; let $name(ref arr2) = other;
let mut ret = [0u64; $n_words]; let mut ret = [0u64; $n_words];
for i in 0..$n_words { for i in 0..$n_words {
ret[i] = arr1[i] & arr2[i]; ret[i] = arr1[i] & arr2[i];
@ -224,9 +224,9 @@ macro_rules! construct_uint {
type Output = $name; type Output = $name;
#[inline] #[inline]
fn bitxor(&self, other: &$name) -> $name { fn bitxor(self, other: $name) -> $name {
let &$name(ref arr1) = self; let $name(ref arr1) = self;
let &$name(ref arr2) = other; let $name(ref arr2) = other;
let mut ret = [0u64; $n_words]; let mut ret = [0u64; $n_words];
for i in 0..$n_words { for i in 0..$n_words {
ret[i] = arr1[i] ^ arr2[i]; ret[i] = arr1[i] ^ arr2[i];
@ -239,9 +239,9 @@ macro_rules! construct_uint {
type Output = $name; type Output = $name;
#[inline] #[inline]
fn bitor(&self, other: &$name) -> $name { fn bitor(self, other: $name) -> $name {
let &$name(ref arr1) = self; let $name(ref arr1) = self;
let &$name(ref arr2) = other; let $name(ref arr2) = other;
let mut ret = [0u64; $n_words]; let mut ret = [0u64; $n_words];
for i in 0..$n_words { for i in 0..$n_words {
ret[i] = arr1[i] | arr2[i]; ret[i] = arr1[i] | arr2[i];
@ -254,8 +254,8 @@ macro_rules! construct_uint {
type Output = $name; type Output = $name;
#[inline] #[inline]
fn not(&self) -> $name { fn not(self) -> $name {
let &$name(ref arr) = self; let $name(ref arr) = self;
let mut ret = [0u64; $n_words]; let mut ret = [0u64; $n_words];
for i in 0..$n_words { for i in 0..$n_words {
ret[i] = !arr[i]; ret[i] = !arr[i];
@ -267,11 +267,11 @@ macro_rules! construct_uint {
impl ::std::ops::Shl<usize> for $name { impl ::std::ops::Shl<usize> for $name {
type Output = $name; type Output = $name;
fn shl(&self, shift: &usize) -> $name { fn shl(self, shift: usize) -> $name {
let &$name(ref original) = self; let $name(ref original) = self;
let mut ret = [0u64; $n_words]; let mut ret = [0u64; $n_words];
let word_shift = *shift / 64; let word_shift = shift / 64;
let bit_shift = *shift % 64; let bit_shift = shift % 64;
for i in 0..$n_words { for i in 0..$n_words {
// Shift // Shift
if bit_shift < 64 && i + word_shift < $n_words { if bit_shift < 64 && i + word_shift < $n_words {
@ -290,11 +290,11 @@ macro_rules! construct_uint {
type Output = $name; type Output = $name;
#[allow(unsigned_negate)] #[allow(unsigned_negate)]
fn shr(&self, shift: &usize) -> $name { fn shr(self, shift: usize) -> $name {
let &$name(ref original) = self; let $name(ref original) = self;
let mut ret = [0u64; $n_words]; let mut ret = [0u64; $n_words];
let word_shift = *shift / 64; let word_shift = shift / 64;
let bit_shift = *shift % 64; let bit_shift = shift % 64;
for i in 0..$n_words { for i in 0..$n_words {
// Shift // Shift
if bit_shift < 64 && i - word_shift < $n_words { if bit_shift < 64 && i - word_shift < $n_words {
@ -329,10 +329,12 @@ macro_rules! construct_uint {
impl fmt::Debug for $name { impl fmt::Debug for $name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use std::fmt::Error; let &$name(ref data) = self;
use network::encodable::ConsensusEncodable; try!(write!(f, "0x"));
let mut encoder = RawEncoder::new(f.by_ref()); for ch in data.iter().rev() {
self.consensus_encode(&mut encoder).map_err(|_| Error) try!(write!(f, "{:02x}", ch));
}
Ok(())
} }
} }
@ -363,7 +365,7 @@ impl Uint256 {
/// Increment by 1 /// Increment by 1
#[inline] #[inline]
pub fn increment(&mut self) { pub fn increment(&mut self) {
let &Uint256(ref mut arr) = self; let &mut Uint256(ref mut arr) = self;
arr[0] += 1; arr[0] += 1;
if arr[0] == 0 { if arr[0] == 0 {
arr[1] += 1; arr[1] += 1;
@ -386,7 +388,7 @@ impl Uint256 {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::io::IoResult; use std::io;
use std::num::from_u64; use std::num::from_u64;
use network::serialize::{deserialize, serialize}; use network::serialize::{deserialize, serialize};
@ -440,7 +442,7 @@ mod tests {
let init: Uint256 = from_u64(0xDEADBEEFDEADBEEF).unwrap(); let init: Uint256 = from_u64(0xDEADBEEFDEADBEEF).unwrap();
let copy = init; let copy = init;
let add = init.add(&copy); let add = init + copy;
assert_eq!(add, Uint256([0xBD5B7DDFBD5B7DDEu64, 1, 0, 0])); assert_eq!(add, Uint256([0xBD5B7DDFBD5B7DDEu64, 1, 0, 0]));
// Bitshifts // Bitshifts
let shl = add << 88; let shl = add << 88;
@ -452,7 +454,7 @@ mod tests {
incr.increment(); incr.increment();
assert_eq!(incr, Uint256([0x7DDE000000000001u64, 0x0001BD5B7DDFBD5B, 0, 0])); assert_eq!(incr, Uint256([0x7DDE000000000001u64, 0x0001BD5B7DDFBD5B, 0, 0]));
// Subtraction // Subtraction
let sub = incr.sub(&init); let sub = incr - init;
assert_eq!(sub, Uint256([0x9F30411021524112u64, 0x0001BD5B7DDFBD5A, 0, 0])); assert_eq!(sub, Uint256([0x9F30411021524112u64, 0x0001BD5B7DDFBD5A, 0, 0]));
// Multiplication // Multiplication
let mult = sub.mul_u32(300); let mult = sub.mul_u32(300);
@ -481,7 +483,7 @@ mod tests {
let init = from_u64::<Uint256>(0xDEADBEEFDEADBEEF).unwrap(); let init = from_u64::<Uint256>(0xDEADBEEFDEADBEEF).unwrap();
assert_eq!(init << 64, Uint256([0, 0xDEADBEEFDEADBEEF, 0, 0])); assert_eq!(init << 64, Uint256([0, 0xDEADBEEFDEADBEEF, 0, 0]));
let add = (init << 64).add(&init); let add = (init << 64) + init;
assert_eq!(add, Uint256([0xDEADBEEFDEADBEEF, 0xDEADBEEFDEADBEEF, 0, 0])); assert_eq!(add, Uint256([0xDEADBEEFDEADBEEF, 0xDEADBEEFDEADBEEF, 0, 0]));
assert_eq!(add >> 0, Uint256([0xDEADBEEFDEADBEEF, 0xDEADBEEFDEADBEEF, 0, 0])); assert_eq!(add >> 0, Uint256([0xDEADBEEFDEADBEEF, 0xDEADBEEFDEADBEEF, 0, 0]));
assert_eq!(add << 0, Uint256([0xDEADBEEFDEADBEEF, 0xDEADBEEFDEADBEEF, 0, 0])); assert_eq!(add << 0, Uint256([0xDEADBEEFDEADBEEF, 0xDEADBEEFDEADBEEF, 0, 0]));
@ -495,8 +497,8 @@ mod tests {
let start2 = Uint256([0x8C8C3EE70C644118u64, 0x0209E7378231E632, 0xABCD, 0xFFFF]); let start2 = Uint256([0x8C8C3EE70C644118u64, 0x0209E7378231E632, 0xABCD, 0xFFFF]);
let serial1 = serialize(&start1).unwrap(); let serial1 = serialize(&start1).unwrap();
let serial2 = serialize(&start2).unwrap(); let serial2 = serialize(&start2).unwrap();
let end1: IoResult<Uint256> = deserialize(serial1); let end1: io::Result<Uint256> = deserialize(serial1);
let end2: IoResult<Uint256> = deserialize(serial2); let end2: io::Result<Uint256> = deserialize(serial2);
assert_eq!(end1, Ok(start1)); assert_eq!(end1, Ok(start1));
assert_eq!(end2, Ok(start2)); assert_eq!(end2, Ok(start2));

View File

@ -19,6 +19,7 @@
use secp256k1::key::PublicKey; use secp256k1::key::PublicKey;
use crypto::digest::Digest; use crypto::digest::Digest;
use crypto::sha2::Sha256; use crypto::sha2::Sha256;
use std::ops;
use blockdata::script::Script; use blockdata::script::Script;
use blockdata::opcodes; use blockdata::opcodes;
@ -36,23 +37,16 @@ pub struct Address {
} }
impl Address { impl Address {
/// Returns a byteslice view of the `Address` --- note that no network information
/// is contained in this.
#[inline]
pub fn as_slice<'a>(&'a self) -> &'a [u8] {
self.hash.as_slice()
}
/// Creates an address from a public key /// Creates an address from a public key
#[inline] #[inline]
pub fn from_key(network: Network, pk: &PublicKey) -> Address { pub fn from_key(network: Network, pk: &PublicKey) -> Address {
let mut sha = Sha256::new(); let mut sha = Sha256::new();
let mut out = [0, ..32]; let mut out = [0;32];
sha.input(pk.as_slice()); sha.input(&pk[..]);
sha.result(out.as_mut_slice()); sha.result(&mut out);
Address { Address {
network: network, network: network,
hash: Ripemd160Hash::from_data(out) hash: Ripemd160Hash::from_data(&out)
} }
} }
@ -62,13 +56,53 @@ impl Address {
let mut script = Script::new(); let mut script = Script::new();
script.push_opcode(opcodes::All::OP_DUP); script.push_opcode(opcodes::All::OP_DUP);
script.push_opcode(opcodes::All::OP_HASH160); script.push_opcode(opcodes::All::OP_HASH160);
script.push_slice(self.hash.as_slice()); script.push_slice(&self.hash[..]);
script.push_opcode(opcodes::All::OP_EQUALVERIFY); script.push_opcode(opcodes::All::OP_EQUALVERIFY);
script.push_opcode(opcodes::All::OP_CHECKSIG); script.push_opcode(opcodes::All::OP_CHECKSIG);
script script
} }
} }
impl ops::Index<usize> for Address {
type Output = u8;
#[inline]
fn index(&self, index: usize) -> &u8 {
&self.hash[index]
}
}
impl ops::Index<ops::Range<usize>> for Address {
type Output = [u8];
#[inline]
fn index(&self, index: ops::Range<usize>) -> &[u8] {
&self.hash[index]
}
}
impl ops::Index<ops::RangeTo<usize>> for Address {
type Output = [u8];
#[inline]
fn index(&self, index: ops::RangeTo<usize>) -> &[u8] {
&self.hash[index]
}
}
impl ops::Index<ops::RangeFrom<usize>> for Address {
type Output = [u8];
#[inline]
fn index(&self, index: ops::RangeFrom<usize>) -> &[u8] {
&self.hash[index]
}
}
impl ops::Index<ops::RangeFull> for Address {
type Output = [u8];
#[inline]
fn index(&self, _: ops::RangeFull) -> &[u8] {
&self.hash[..]
}
}
/// Conversion from other types into an address /// Conversion from other types into an address
pub trait ToAddress { pub trait ToAddress {
/// Copies `self` into a new `Address` /// Copies `self` into a new `Address`
@ -93,7 +127,7 @@ impl ToBase58 for Address {
Network::Testnet => 111 Network::Testnet => 111
} }
]; ];
ret.push_all(self.hash.as_slice()); ret.push_all(&self.hash[..]);
ret ret
} }
} }
@ -110,7 +144,7 @@ impl FromBase58 for Address {
111 => Network::Testnet, 111 => Network::Testnet,
x => { return Err(base58::Error::InvalidVersion(vec![x])); } x => { return Err(base58::Error::InvalidVersion(vec![x])); }
}, },
hash: Ripemd160Hash::from_slice(data.slice_from(1)) hash: Ripemd160Hash::from_slice(&data[1..])
}) })
} }
} }
@ -137,10 +171,10 @@ mod tests {
fn test_address_58() { fn test_address_58() {
let addr = Address { let addr = Address {
network: Bitcoin, network: Bitcoin,
hash: Ripemd160Hash::from_slice("162c5ea71c0b23f5b9022ef047c4a86470a5b070".from_hex().unwrap().as_slice()) hash: Ripemd160Hash::from_slice(&"162c5ea71c0b23f5b9022ef047c4a86470a5b070".from_hex().unwrap())
}; };
assert_eq!(addr.to_base58check().as_slice(), "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM"); assert_eq!(&addr.to_base58check(), "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM");
assert_eq!(FromBase58::from_base58check("132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM"), Ok(addr)); assert_eq!(FromBase58::from_base58check("132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM"), Ok(addr));
} }

View File

@ -19,7 +19,7 @@
//! //!
use std::collections::HashMap; use std::collections::HashMap;
use std::hash::{hash, Hash, SipHasher}; use std::hash::{hash, Hash, Hasher, SipHasher};
use secp256k1::key::SecretKey; use secp256k1::key::SecretKey;
@ -61,7 +61,7 @@ pub struct WalletTxOut {
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
pub struct AddressIndex { pub struct AddressIndex {
tentative_index: HashMap<Script, Vec<WalletTxOut>>, tentative_index: HashMap<Script, Vec<WalletTxOut>>,
index: HashMap<(Sha256dHash, u32), Vec<WalletTxOut>, SipHasher>, index: HashMap<(Sha256dHash, u32), Vec<WalletTxOut>>,
network: Network, network: Network,
k1: u64, k1: u64,
k2: u64 k2: u64
@ -74,7 +74,7 @@ impl AddressIndex {
let (k1, k2) = wallet.siphash_key(); let (k1, k2) = wallet.siphash_key();
let mut ret = AddressIndex { let mut ret = AddressIndex {
tentative_index: HashMap::with_capacity(utxo_set.n_utxos() / 256), tentative_index: HashMap::with_capacity(utxo_set.n_utxos() / 256),
index: HashMap::with_hasher(SipHasher::new()), index: HashMap::new(),
network: wallet.network(), network: wallet.network(),
k1: k1, k1: k1,
k2: k2 k2: k2
@ -88,7 +88,9 @@ impl AddressIndex {
txo: txo.clone(), txo: txo.clone(),
kind: WalletTxOutType::Unknown kind: WalletTxOutType::Unknown
}; };
ret.tentative_index.find_or_insert(txo.script_pubkey.clone(), vec![]).push(new); let mut entry = ret.tentative_index.entry(txo.script_pubkey.clone());
let txos = entry.or_insert(vec![]);
txos.push(new);
} }
} }
ret ret
@ -99,14 +101,16 @@ impl AddressIndex {
pub fn index_wallet_txo(&mut self, wtx: &WalletTxOut, kind: WalletTxOutType) { pub fn index_wallet_txo(&mut self, wtx: &WalletTxOut, kind: WalletTxOutType) {
let mut new = wtx.clone(); let mut new = wtx.clone();
new.kind = kind; new.kind = kind;
self.index.find_or_insert((wtx.txid, wtx.vout), vec![]).push(new); let mut entry = self.index.entry((wtx.txid, wtx.vout));
let txos = entry.or_insert(vec![]);
txos.push(new);
} }
/// A filtering function used for creating a small address index. /// A filtering function used for creating a small address index.
#[inline] #[inline]
pub fn admissible_address(&self, addr: &Address) -> bool { pub fn admissible_address(&self, addr: &Address) -> bool {
let mut hasher = SipHasher::new_with_keys(self.k1, self.k2); let mut hasher = SipHasher::new_with_keys(self.k1, self.k2);
addr.hash(&mut hasher); (&addr[..]).hash(&mut hasher);
hasher.finish() & 0xFF == 0 hasher.finish() & 0xFF == 0
} }
@ -123,7 +127,7 @@ impl AddressIndex {
/// may be more than one for any given scriptpubkey. /// may be more than one for any given scriptpubkey.
#[inline] #[inline]
pub fn find_by_script<'a>(&'a self, pubkey: &Script) -> &'a [WalletTxOut] { pub fn find_by_script<'a>(&'a self, pubkey: &Script) -> &'a [WalletTxOut] {
self.tentative_index.find(pubkey).map(|v| v.as_slice()).unwrap_or(&[]) self.tentative_index.get(pubkey).map(|v| &v[..]).unwrap_or(&[])
} }
} }

View File

@ -17,9 +17,9 @@
//! at https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki //! at https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
use std::default::Default; use std::default::Default;
use serde; use serde::{Serialize, Deserialize, Serializer, Deserializer};
use byteorder::{ByteOrder, BigEndian}; use crypto::cryptoutil::{read_u32_be, write_u32_be};
use crypto::digest::Digest; use crypto::digest::Digest;
use crypto::hmac::Hmac; use crypto::hmac::Hmac;
use crypto::mac::Mac; use crypto::mac::Mac;
@ -92,9 +92,9 @@ pub enum ChildNumber {
Normal(u32), Normal(u32),
} }
impl serde::Serialize for ChildNumber { impl Serialize for ChildNumber {
fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error>
where S: serde::Serializer { where S: Serializer {
match *self { match *self {
ChildNumber::Hardened(n) => (n + (1 << 31)).serialize(s), ChildNumber::Hardened(n) => (n + (1 << 31)).serialize(s),
ChildNumber::Normal(n) => n.serialize(s) ChildNumber::Normal(n) => n.serialize(s)
@ -102,10 +102,10 @@ impl serde::Serialize for ChildNumber {
} }
} }
impl serde::Deserialize for ChildNumber { impl Deserialize for ChildNumber {
fn deserialize<D>(&self, d: &mut D) -> Result<ChildNumber, D::Error> fn deserialize<D>(d: &mut D) -> Result<ChildNumber, D::Error>
where D: serde::Deserializer { where D: Deserializer {
let n: u32 = try!(serde::Deserialize::decode(d)); let n: u32 = try!(Deserialize::deserialize(d));
if n < (1 << 31) { if n < (1 << 31) {
Ok(ChildNumber::Normal(n)) Ok(ChildNumber::Normal(n))
} else { } else {
@ -120,7 +120,7 @@ pub enum Error {
/// A pk->pk derivation was attempted on a hardened key /// A pk->pk derivation was attempted on a hardened key
CannotDeriveFromHardenedKey, CannotDeriveFromHardenedKey,
/// A secp256k1 error occured /// A secp256k1 error occured
EcdsaError(secp256k1::Error), Ecdsa(secp256k1::Error),
/// A child number was provided that was out of range /// A child number was provided that was out of range
InvalidChildNumber(ChildNumber), InvalidChildNumber(ChildNumber),
/// Error creating a master seed --- for application use /// Error creating a master seed --- for application use
@ -131,17 +131,17 @@ impl ExtendedPrivKey {
/// Construct a new master key from a seed value /// Construct a new master key from a seed value
pub fn new_master(network: Network, seed: &[u8]) -> Result<ExtendedPrivKey, Error> { pub fn new_master(network: Network, seed: &[u8]) -> Result<ExtendedPrivKey, Error> {
let mut result = [0; 64]; let mut result = [0; 64];
let mut hmac = Hmac::new(Sha512::new(), b"Bitcoin seed".as_slice()); let mut hmac = Hmac::new(Sha512::new(), b"Bitcoin seed");
hmac.input(seed); hmac.input(seed);
hmac.raw_result(result.as_mut_slice()); hmac.raw_result(&mut result);
Ok(ExtendedPrivKey { Ok(ExtendedPrivKey {
network: network, network: network,
depth: 0, depth: 0,
parent_fingerprint: Default::default(), parent_fingerprint: Default::default(),
child_number: ChildNumber::Normal(0), child_number: ChildNumber::Normal(0),
secret_key: try!(SecretKey::from_slice(result.slice_to(32)).map_err(Error::EcdsaError)), secret_key: try!(SecretKey::from_slice(&result[..32]).map_err(Error::Ecdsa)),
chain_code: ChainCode::from_slice(result.slice_from(32)) chain_code: ChainCode::from_slice(&result[32..])
}) })
} }
@ -158,27 +158,29 @@ impl ExtendedPrivKey {
/// Private->Private child key derivation /// Private->Private child key derivation
pub fn ckd_priv(&self, i: ChildNumber) -> Result<ExtendedPrivKey, Error> { pub fn ckd_priv(&self, i: ChildNumber) -> Result<ExtendedPrivKey, Error> {
let mut result = [0; 64]; let mut result = [0; 64];
let mut hmac = Hmac::new(Sha512::new(), self.chain_code.as_slice()); let mut hmac = Hmac::new(Sha512::new(), &self.chain_code[..]);
let mut be_n = [0; 32];
match i { match i {
ChildNumber::Normal(n) => { ChildNumber::Normal(n) => {
if n >= (1 << 31) { return Err(Error::InvalidChildNumber(i)) } if n >= (1 << 31) { return Err(Error::InvalidChildNumber(i)) }
// Non-hardened key: compute public data and use that // Non-hardened key: compute public data and use that
secp256k1::init(); secp256k1::init();
// Note the unwrap: this is fine, we checked the SK when we created it // Note the unwrap: this is fine, we checked the SK when we created it
hmac.input(PublicKey::from_secret_key(&self.secret_key, true).as_slice()); hmac.input(&PublicKey::from_secret_key(&self.secret_key, true)[..]);
hmac.write_u32::<BigEndian>(n); write_u32_be(&mut be_n, n);
} }
ChildNumber::Hardened(n) => { ChildNumber::Hardened(n) => {
if n >= (1 << 31) { return Err(Error::InvalidChildNumber(i)) } if n >= (1 << 31) { return Err(Error::InvalidChildNumber(i)) }
// Hardened key: use only secret data to prevent public derivation // Hardened key: use only secret data to prevent public derivation
hmac.input([0]); hmac.input(&[0u8]);
hmac.input(self.secret_key.as_slice()); hmac.input(&self.secret_key[..]);
hmac.write_u32::<BigEndian>(n + (1 << 31)); write_u32_be(&mut be_n, n + (1 << 31));
} }
} }
hmac.raw_result(result.as_mut_slice()); hmac.input(&be_n);
let mut sk = try!(SecretKey::from_slice(result.slice_to(32)).map_err(Error::EcdsaError)); hmac.raw_result(&mut result);
try!(sk.add_assign(&self.secret_key).map_err(Error::EcdsaError)); let mut sk = try!(SecretKey::from_slice(&result[..32]).map_err(Error::Ecdsa));
try!(sk.add_assign(&self.secret_key).map_err(Error::Ecdsa));
Ok(ExtendedPrivKey { Ok(ExtendedPrivKey {
network: self.network, network: self.network,
@ -186,7 +188,7 @@ impl ExtendedPrivKey {
parent_fingerprint: self.fingerprint(), parent_fingerprint: self.fingerprint(),
child_number: i, child_number: i,
secret_key: sk, secret_key: sk,
chain_code: ChainCode::from_slice(result.slice_from(32)) chain_code: ChainCode::from_slice(&result[32..])
}) })
} }
@ -198,19 +200,19 @@ impl ExtendedPrivKey {
let pk = ExtendedPubKey::from_private(self); let pk = ExtendedPubKey::from_private(self);
// Do SHA256 of just the ECDSA pubkey // Do SHA256 of just the ECDSA pubkey
let mut sha2 = Sha256::new(); let mut sha2 = Sha256::new();
sha2.input(pk.public_key.as_slice()); sha2.input(&pk.public_key[..]);
sha2.result(sha2_res.as_mut_slice()); sha2.result(&mut sha2_res);
// do RIPEMD160 // do RIPEMD160
let mut ripemd = Ripemd160::new(); let mut ripemd = Ripemd160::new();
ripemd.input(sha2_res.as_slice()); ripemd.input(&sha2_res);
ripemd.result(ripemd_res.as_mut_slice()); ripemd.result(&mut ripemd_res);
// Return // Return
ripemd_res ripemd_res
} }
/// Returns the first four bytes of the identifier /// Returns the first four bytes of the identifier
pub fn fingerprint(&self) -> Fingerprint { pub fn fingerprint(&self) -> Fingerprint {
Fingerprint::from_slice(self.identifier().slice_to(4)) Fingerprint::from_slice(&self.identifier()[0..4])
} }
} }
@ -239,16 +241,18 @@ impl ExtendedPubKey {
} }
} }
ChildNumber::Normal(n) => { ChildNumber::Normal(n) => {
let mut hmac = Hmac::new(Sha512::new(), self.chain_code.as_slice()); let mut hmac = Hmac::new(Sha512::new(), &self.chain_code[..]);
hmac.input(self.public_key.as_slice()); hmac.input(&self.public_key[..]);
hmac.write_u32::<BigEndian>(n); let mut be_n = [0; 32];
write_u32_be(&mut be_n, n);
hmac.input(&be_n);
let mut result = [0; 64]; let mut result = [0; 64];
hmac.raw_result(result.as_mut_slice()); hmac.raw_result(&mut result);
let sk = try!(SecretKey::from_slice(result.slice_to(32)).map_err(Error::EcdsaError)); let sk = try!(SecretKey::from_slice(&result[..32]).map_err(Error::Ecdsa));
let mut pk = self.public_key.clone(); let mut pk = self.public_key.clone();
try!(pk.add_exp_assign(&sk).map_err(Error::EcdsaError)); try!(pk.add_exp_assign(&sk).map_err(Error::Ecdsa));
Ok(ExtendedPubKey { Ok(ExtendedPubKey {
network: self.network, network: self.network,
@ -256,7 +260,7 @@ impl ExtendedPubKey {
parent_fingerprint: self.fingerprint(), parent_fingerprint: self.fingerprint(),
child_number: i, child_number: i,
public_key: pk, public_key: pk,
chain_code: ChainCode::from_slice(result.slice_from(32)) chain_code: ChainCode::from_slice(&result[32..])
}) })
} }
} }
@ -268,19 +272,19 @@ impl ExtendedPubKey {
let mut ripemd_res = [0; 20]; let mut ripemd_res = [0; 20];
// Do SHA256 of just the ECDSA pubkey // Do SHA256 of just the ECDSA pubkey
let mut sha2 = Sha256::new(); let mut sha2 = Sha256::new();
sha2.input(self.public_key.as_slice()); sha2.input(&self.public_key[..]);
sha2.result(sha2_res.as_mut_slice()); sha2.result(&mut sha2_res);
// do RIPEMD160 // do RIPEMD160
let mut ripemd = Ripemd160::new(); let mut ripemd = Ripemd160::new();
ripemd.input(sha2_res.as_slice()); ripemd.input(&sha2_res);
ripemd.result(ripemd_res.as_mut_slice()); ripemd.result(&mut ripemd_res);
// Return // Return
ripemd_res ripemd_res
} }
/// Returns the first four bytes of the identifier /// Returns the first four bytes of the identifier
pub fn fingerprint(&self) -> Fingerprint { pub fn fingerprint(&self) -> Fingerprint {
Fingerprint::from_slice(self.identifier().slice_to(4)) Fingerprint::from_slice(&self.identifier()[0..4])
} }
} }
@ -288,22 +292,24 @@ impl ToBase58 for ExtendedPrivKey {
fn base58_layout(&self) -> Vec<u8> { fn base58_layout(&self) -> Vec<u8> {
let mut ret = Vec::with_capacity(78); let mut ret = Vec::with_capacity(78);
ret.push_all(match self.network { ret.push_all(match self.network {
Network::Bitcoin => [0x04, 0x88, 0xAD, 0xE4], Network::Bitcoin => &[0x04, 0x88, 0xAD, 0xE4],
Network::Testnet => [0x04, 0x35, 0x83, 0x94] Network::Testnet => &[0x04, 0x35, 0x83, 0x94]
}); });
ret.push(self.depth as u8); ret.push(self.depth as u8);
ret.push_all(self.parent_fingerprint.as_slice()); ret.push_all(&self.parent_fingerprint[..]);
let mut be_n = [0; 32];
match self.child_number { match self.child_number {
ChildNumber::Hardened(n) => { ChildNumber::Hardened(n) => {
ret.write_u32::<BigEndian>(n + (1 << 31)); write_u32_be(&mut be_n, n + (1 << 31));
} }
ChildNumber::Normal(n) => { ChildNumber::Normal(n) => {
ret.write_u32::<BigEndian>(n); write_u32_be(&mut be_n, n);
} }
} }
ret.push_all(self.chain_code.as_slice()); ret.push_all(&be_n);
ret.push_all(&self.chain_code[..]);
ret.push(0); ret.push(0);
ret.push_all(self.secret_key.as_slice()); ret.push_all(&self.secret_key[..]);
ret ret
} }
} }
@ -314,22 +320,22 @@ impl FromBase58 for ExtendedPrivKey {
return Err(base58::Error::InvalidLength(data.len())); return Err(base58::Error::InvalidLength(data.len()));
} }
let cn_int = BigEndian::read_u32(&data[9..13]); let cn_int = read_u32_be(&data[9..13]);
let child_number = if cn_int < (1 << 31) { ChildNumber::Normal(cn_int) } let child_number = if cn_int < (1 << 31) { ChildNumber::Normal(cn_int) }
else { ChildNumber::Hardened(cn_int - (1 << 31)) }; else { ChildNumber::Hardened(cn_int - (1 << 31)) };
Ok(ExtendedPrivKey { Ok(ExtendedPrivKey {
network: match data.slice_to(4) { network: match &data[0..4] {
[0x04, 0x88, 0xAD, 0xE4] => Network::Bitcoin, [0x04u8, 0x88, 0xAD, 0xE4] => Network::Bitcoin,
[0x04, 0x35, 0x83, 0x94] => Network::Testnet, [0x04u8, 0x35, 0x83, 0x94] => Network::Testnet,
_ => { return Err(base58::Error::InvalidVersion(data.slice_to(4).to_vec())); } _ => { return Err(base58::Error::InvalidVersion((&data[0..4]).to_vec())); }
}, },
depth: data[4], depth: data[4],
parent_fingerprint: Fingerprint::from_slice(data.slice(5, 9)), parent_fingerprint: Fingerprint::from_slice(&data[5..9]),
child_number: child_number, child_number: child_number,
chain_code: ChainCode::from_slice(data.slice(13, 45)), chain_code: ChainCode::from_slice(&data[13..45]),
secret_key: try!(SecretKey::from_slice( secret_key: try!(SecretKey::from_slice(
data.slice(46, 78)).map_err(|e| &data[46..78]).map_err(|e|
base58::Error::Other(e.to_string()))) base58::Error::Other(e.to_string())))
}) })
} }
@ -340,21 +346,23 @@ impl ToBase58 for ExtendedPubKey {
assert!(self.public_key.is_compressed()); assert!(self.public_key.is_compressed());
let mut ret = Vec::with_capacity(78); let mut ret = Vec::with_capacity(78);
ret.push_all(match self.network { ret.push_all(match self.network {
Network::Bitcoin => [0x04, 0x88, 0xB2, 0x1E], Network::Bitcoin => &[0x04u8, 0x88, 0xB2, 0x1E],
Network::Testnet => [0x04, 0x35, 0x87, 0xCF] Network::Testnet => &[0x04u8, 0x35, 0x87, 0xCF]
}); });
ret.push(self.depth as u8); ret.push(self.depth as u8);
ret.push_all(self.parent_fingerprint.as_slice()); ret.push_all(&self.parent_fingerprint[..]);
let mut be_n = [0; 32];
match self.child_number { match self.child_number {
ChildNumber::Hardened(n) => { ChildNumber::Hardened(n) => {
ret.write_u32::<BigEndian>(n + (1 << 31)); write_u32_be(&mut be_n, n + (1 << 31));
} }
ChildNumber::Normal(n) => { ChildNumber::Normal(n) => {
ret.write_u32::<BigEndian>(n); write_u32_be(&mut be_n, n);
} }
} }
ret.push_all(self.chain_code.as_slice()); ret.push_all(&be_n);
ret.push_all(self.public_key.as_slice()); ret.push_all(&self.chain_code[..]);
ret.push_all(&self.public_key[..]);
ret ret
} }
} }
@ -365,22 +373,22 @@ impl FromBase58 for ExtendedPubKey {
return Err(base58::Error::InvalidLength(data.len())); return Err(base58::Error::InvalidLength(data.len()));
} }
let cn_int = BigEndian::read_u32(&data[9..13]); let cn_int = read_u32_be(&data[9..13]);
let child_number = if cn_int < (1 << 31) { ChildNumber::Normal(cn_int) } let child_number = if cn_int < (1 << 31) { ChildNumber::Normal(cn_int) }
else { ChildNumber::Hardened(cn_int - (1 << 31)) }; else { ChildNumber::Hardened(cn_int - (1 << 31)) };
Ok(ExtendedPubKey { Ok(ExtendedPubKey {
network: match data.slice_to(4) { network: match &data[0..4] {
[0x04, 0x88, 0xB2, 0x1E] => Network::Bitcoin, [0x04, 0x88, 0xB2, 0x1E] => Network::Bitcoin,
[0x04, 0x35, 0x87, 0xCF] => Network::Testnet, [0x04, 0x35, 0x87, 0xCF] => Network::Testnet,
_ => { return Err(base58::Error::InvalidVersion(data.slice_to(4).to_vec())); } _ => { return Err(base58::Error::InvalidVersion((&data[0..4]).to_vec())); }
}, },
depth: data[4], depth: data[4],
parent_fingerprint: Fingerprint::from_slice(data.slice(5, 9)), parent_fingerprint: Fingerprint::from_slice(&data[5..9]),
child_number: child_number, child_number: child_number,
chain_code: ChainCode::from_slice(data.slice(13, 45)), chain_code: ChainCode::from_slice(&data[13..45]),
public_key: try!(PublicKey::from_slice( public_key: try!(PublicKey::from_slice(
data.slice(45, 78)).map_err(|e| &data[45..78]).map_err(|e|
base58::Error::Other(e.to_string()))) base58::Error::Other(e.to_string())))
}) })
} }
@ -421,8 +429,8 @@ mod tests {
} }
// Check result against expected base58 // Check result against expected base58
assert_eq!(sk.to_base58check().as_slice(), expected_sk); assert_eq!(&sk.to_base58check()[..], expected_sk);
assert_eq!(pk.to_base58check().as_slice(), expected_pk); assert_eq!(&pk.to_base58check()[..], expected_pk);
// Check decoded base58 against result // Check decoded base58 against result
let decoded_sk = FromBase58::from_base58check(expected_sk); let decoded_sk = FromBase58::from_base58check(expected_sk);
let decoded_pk = FromBase58::from_base58check(expected_pk); let decoded_pk = FromBase58::from_base58check(expected_pk);
@ -434,32 +442,32 @@ mod tests {
fn test_vector_1() { fn test_vector_1() {
let seed = "000102030405060708090a0b0c0d0e0f".from_hex().unwrap(); let seed = "000102030405060708090a0b0c0d0e0f".from_hex().unwrap();
// m // m
test_path(Bitcoin, seed.as_slice(), [], test_path(Bitcoin, &seed, [],
"xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi", "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
"xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"); "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8");
// m/0h // m/0h
test_path(Bitcoin, seed.as_slice(), [Hardened(0)], test_path(Bitcoin, &seed, [Hardened(0)],
"xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7", "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7",
"xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw"); "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw");
// m/0h/1 // m/0h/1
test_path(Bitcoin, seed.as_slice(), [Hardened(0), Normal(1)], test_path(Bitcoin, &seed, [Hardened(0), Normal(1)],
"xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs", "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs",
"xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ"); "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ");
// m/0h/1/2h // m/0h/1/2h
test_path(Bitcoin, seed.as_slice(), [Hardened(0), Normal(1), Hardened(2)], test_path(Bitcoin, &seed, [Hardened(0), Normal(1), Hardened(2)],
"xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM", "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM",
"xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5"); "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5");
// m/0h/1/2h/2 // m/0h/1/2h/2
test_path(Bitcoin, seed.as_slice(), [Hardened(0), Normal(1), Hardened(2), Normal(2)], test_path(Bitcoin, &seed, [Hardened(0), Normal(1), Hardened(2), Normal(2)],
"xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334", "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334",
"xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV"); "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV");
// m/0h/1/2h/2/1000000000 // m/0h/1/2h/2/1000000000
test_path(Bitcoin, seed.as_slice(), [Hardened(0), Normal(1), Hardened(2), Normal(2), Normal(1000000000)], test_path(Bitcoin, &seed, [Hardened(0), Normal(1), Hardened(2), Normal(2), Normal(1000000000)],
"xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76", "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76",
"xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy"); "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy");
} }
@ -469,32 +477,32 @@ mod tests {
let seed = "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542".from_hex().unwrap(); let seed = "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542".from_hex().unwrap();
// m // m
test_path(Bitcoin, seed.as_slice(), [], test_path(Bitcoin, &seed, [],
"xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U", "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U",
"xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB"); "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB");
// m/0 // m/0
test_path(Bitcoin, seed.as_slice(), [Normal(0)], test_path(Bitcoin, &seed, [Normal(0)],
"xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt", "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt",
"xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH"); "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH");
// m/0/2147483647h // m/0/2147483647h
test_path(Bitcoin, seed.as_slice(), [Normal(0), Hardened(2147483647)], test_path(Bitcoin, &seed, [Normal(0), Hardened(2147483647)],
"xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9", "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9",
"xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a"); "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a");
// m/0/2147483647h/1 // m/0/2147483647h/1
test_path(Bitcoin, seed.as_slice(), [Normal(0), Hardened(2147483647), Normal(1)], test_path(Bitcoin, &seed, [Normal(0), Hardened(2147483647), Normal(1)],
"xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef", "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef",
"xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon"); "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon");
// m/0/2147483647h/1/2147483646h // m/0/2147483647h/1/2147483646h
test_path(Bitcoin, seed.as_slice(), [Normal(0), Hardened(2147483647), Normal(1), Hardened(2147483646)], test_path(Bitcoin, &seed, [Normal(0), Hardened(2147483647), Normal(1), Hardened(2147483646)],
"xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc", "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc",
"xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"); "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL");
// m/0/2147483647h/1/2147483646h/2 // m/0/2147483647h/1/2147483646h/2
test_path(Bitcoin, seed.as_slice(), [Normal(0), Hardened(2147483647), Normal(1), Hardened(2147483646), Normal(2)], test_path(Bitcoin, &seed, [Normal(0), Hardened(2147483647), Normal(1), Hardened(2147483646), Normal(2)],
"xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j", "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j",
"xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt"); "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt");
} }
@ -512,8 +520,8 @@ mod tests {
assert!(h1 != n1); assert!(h1 != n1);
assert!(h1_str != n1_str); assert!(h1_str != n1_str);
let h1_dec = json::decode(h1_str.as_slice()).unwrap(); let h1_dec = json::decode(&h1_str).unwrap();
let n1_dec = json::decode(n1_str.as_slice()).unwrap(); let n1_dec = json::decode(&n1_str).unwrap();
assert_eq!(h1, h1_dec); assert_eq!(h1, h1_dec);
assert_eq!(n1, n1_dec); assert_eq!(n1, n1_dec);
} }
@ -521,7 +529,7 @@ mod tests {
#[bench] #[bench]
pub fn generate_sequential_normal_children(bh: &mut Bencher) { pub fn generate_sequential_normal_children(bh: &mut Bencher) {
let seed = "000102030405060708090a0b0c0d0e0f".from_hex().unwrap(); let seed = "000102030405060708090a0b0c0d0e0f".from_hex().unwrap();
let msk = ExtendedPrivKey::new_master(Bitcoin, seed.as_slice()).unwrap(); let msk = ExtendedPrivKey::new_master(Bitcoin, &seed).unwrap();
let mut i = 0; let mut i = 0;
bh.iter( || { bh.iter( || {
black_box(msk.ckd_priv(Normal(i))); black_box(msk.ckd_priv(Normal(i)));
@ -532,7 +540,7 @@ mod tests {
#[bench] #[bench]
pub fn generate_sequential_hardened_children(bh: &mut Bencher) { pub fn generate_sequential_hardened_children(bh: &mut Bencher) {
let seed = "000102030405060708090a0b0c0d0e0f".from_hex().unwrap(); let seed = "000102030405060708090a0b0c0d0e0f".from_hex().unwrap();
let msk = ExtendedPrivKey::new_master(Bitcoin, seed.as_slice()).unwrap(); let msk = ExtendedPrivKey::new_master(Bitcoin, &seed).unwrap();
let mut i = 0; let mut i = 0;
bh.iter( || { bh.iter( || {
black_box(msk.ckd_priv(Hardened(i))); black_box(msk.ckd_priv(Hardened(i)));
@ -543,7 +551,7 @@ mod tests {
#[bench] #[bench]
pub fn generate_sequential_public_children(bh: &mut Bencher) { pub fn generate_sequential_public_children(bh: &mut Bencher) {
let seed = "000102030405060708090a0b0c0d0e0f".from_hex().unwrap(); let seed = "000102030405060708090a0b0c0d0e0f".from_hex().unwrap();
let msk = ExtendedPrivKey::new_master(Bitcoin, seed.as_slice()).unwrap(); let msk = ExtendedPrivKey::new_master(Bitcoin, &seed).unwrap();
let mpk = ExtendedPubKey::from_private(&msk); let mpk = ExtendedPubKey::from_private(&msk);
let mut i = 0; let mut i = 0;
@ -558,7 +566,7 @@ mod tests {
use wallet::address::Address; use wallet::address::Address;
let seed = "000102030405060708090a0b0c0d0e0f".from_hex().unwrap(); let seed = "000102030405060708090a0b0c0d0e0f".from_hex().unwrap();
let msk = ExtendedPrivKey::new_master(Bitcoin, seed.as_slice()).unwrap(); let msk = ExtendedPrivKey::new_master(Bitcoin, &seed).unwrap();
let mpk = ExtendedPubKey::from_private(&msk); let mpk = ExtendedPubKey::from_private(&msk);
let mut i = 0; let mut i = 0;

View File

@ -18,7 +18,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::default::Default; use std::default::Default;
use serde; use serde::{Serialize, Deserialize, Serializer, Deserializer};
use secp256k1::key::PublicKey; use secp256k1::key::PublicKey;
@ -85,23 +85,23 @@ pub struct Wallet {
index: Option<AddressIndex> index: Option<AddressIndex>
} }
impl serde::Serialize for Wallet { impl Serialize for Wallet {
fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error>
where S: serde::Serializer { where S: Serializer {
let len = self.accounts.len(); let len = self.accounts.len();
try!(self.master.serialize(s)); try!(self.master.serialize(s));
self.accounts.serialize(s) self.accounts.serialize(s)
} }
} }
impl serde::Deserialize for Wallet { impl Deserialize for Wallet {
fn deserialize<D>(&self, d: &mut D) -> Result<Wallet, D::Error> fn deserialize<D>(d: &mut D) -> Result<Wallet, D::Error>
where D: serde::Deserializer { where D: Deserializer {
Wallet { Ok(Wallet {
master: try!(serde::Deserialize::deserialize(d)), master: try!(Deserialize::deserialize(d)),
accounts: try!(serde::Deserialize::deserialize(d)), accounts: try!(Deserialize::deserialize(d)),
index: None index: None
} })
} }
} }
@ -141,7 +141,7 @@ impl Wallet {
/// Adds an account to a wallet /// Adds an account to a wallet
pub fn account_insert(&mut self, name: String) pub fn account_insert(&mut self, name: String)
-> Result<(), Error> { -> Result<(), Error> {
if self.accounts.find(&name).is_some() { if self.accounts.contains_key(&name) {
return Err(Error::DuplicateAccount); return Err(Error::DuplicateAccount);
} }
@ -159,9 +159,8 @@ impl Wallet {
/// Locates an account in a wallet /// Locates an account in a wallet
#[inline] #[inline]
pub fn account_find<'a>(&'a self, name: &str) pub fn account_get<'a>(&'a self, name: &str) -> Option<&'a Account> {
-> Option<&'a Account> { self.accounts.get(name)
self.accounts.find_equiv(&name)
} }
/// Create a new address /// Create a new address
@ -169,8 +168,7 @@ impl Wallet {
account: &str, account: &str,
chain: AccountChain) chain: AccountChain)
-> Result<Address, Error> { -> Result<Address, Error> {
// TODO: unnecessary allocation, waiting on *_equiv in stdlib let account = self.accounts.get_mut(account);
let account = self.accounts.find_mut(&account.to_string());
let account = match account { Some(a) => a, None => return Err(Error::AccountNotFound) }; let account = match account { Some(a) => a, None => return Err(Error::AccountNotFound) };
let index = match self.index { Some(ref i) => i, None => return Err(Error::NoAddressIndex) }; let index = match self.index { Some(ref i) => i, None => return Err(Error::NoAddressIndex) };
@ -236,7 +234,7 @@ impl Wallet {
/// Account balance /// Account balance
pub fn balance(&self, account: &str) -> Result<u64, Error> { pub fn balance(&self, account: &str) -> Result<u64, Error> {
let account = self.accounts.find_equiv(&account); let account = self.accounts.get(account);
let account = match account { Some(a) => a, None => return Err(Error::AccountNotFound) }; let account = match account { Some(a) => a, None => return Err(Error::AccountNotFound) };
self.account_balance(account) self.account_balance(account)
} }