Initial commit, move into Cargo

This commit is contained in:
Andrew Poelstra 2014-07-18 06:56:17 -07:00
commit c9ad7c0b58
28 changed files with 5298 additions and 0 deletions

18
Cargo.toml Normal file
View File

@ -0,0 +1,18 @@
[package]
name = "bitcoin-rs"
version = "0.0.1"
authors = ["Andrew Poelstra <apoelstra@wpsoftware.net>"]
[[lib]]
name = "bitcoin"
path = "src/lib.rs"
[dependencies.rust-crypto]
git = "https://github.com/DaGenix/rust-crypto.git"

158
src/blockdata/block.rs Normal file
View File

@ -0,0 +1,158 @@
// 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/>.
//
//! # Bitcoin Block
//!
//! A block is a bundle of transactions with a proof-of-work attached,
//! which attaches to an earlier block to form the blockchain. This
//! module describes structures and functions needed to describe
//! these blocks and the blockchain.
//!
use std::io::IoResult;
use std::num::{Zero, from_u64};
use util::hash::Sha256dHash;
use util::uint::Uint256;
use network::serialize::{Serializable, SerializeIter, VarInt};
use blockdata::transaction::Transaction;
/// A block header, which contains all the block's information except
/// the actual transactions
#[deriving(PartialEq, Show)]
pub struct BlockHeader {
/// The protocol version. Should always be 1.
pub version: u32,
/// Reference to the previous block in the chain
pub prev_blockhash: Sha256dHash,
/// The root hash of the merkle tree of transactions in the block
pub merkle_root: Sha256dHash,
/// The timestamp of the block, as claimed by the mainer
pub time: u32,
/// The target value below which the blockhash must lie, encoded as a
/// a float (with well-defined rounding, of course)
pub bits: u32,
/// The nonce, selected to obtain a low enough blockhash
pub nonce: u32,
}
/// A Bitcoin block, which is a collection of transactions with an attached
/// proof of work.
#[deriving(PartialEq, Show)]
pub struct Block {
/// The block header
pub header: BlockHeader,
/// List of transactions contained in the block
pub txdata: Vec<Transaction>
}
/// A block header with txcount attached, which is given in the `headers`
/// network message.
#[deriving(PartialEq, Show)]
pub struct LoneBlockHeader {
/// The actual block header
pub header: BlockHeader,
/// The number of transactions in the block. This will always be zero
/// when the LoneBlockHeader is returned as part ef a `headers` message.
pub tx_count: VarInt
}
impl BlockHeader {
/// Computes the target [0, T] that a blockhash must land in to be valid
pub fn target(&self) -> Uint256 {
// This is a floating-point "compact" encoding originally used by
// OpenSSL, which satoshi put into consensus code, so we're stuck
// with it. The exponent needs to have 3 subtracted from it, hence
// this goofy decoding code:
let (mant, expt) = {
let unshifted_expt = self.bits >> 24;
if unshifted_expt <= 3 {
((self.bits & 0xFFFFFF) >> 8 * (3 - unshifted_expt as uint), 0)
} else {
(self.bits & 0xFFFFFF, 8 * ((self.bits >> 24) - 3))
}
};
// The mantissa is signed but may not be negative
if mant > 0x7FFFFF {
Zero::zero()
} else {
from_u64::<Uint256>(mant as u64).unwrap() << (expt as uint)
}
}
/// 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
/// correctly.
pub fn spv_validate(&self, required_target: &Uint256) -> bool {
let ref target = self.target();
if target != required_target {
return false;
}
let ref hash = self.hash().as_uint256();
hash <= target
}
/// Returns the total work of the block
pub fn work(&self) -> Uint256 {
// 2**256 / (target + 1) == ~target / (target+1) + 1 (eqn shamelessly stolen from bitcoind)
let mut ret = !self.target();
let mut ret1 = self.target();
ret1.increment();
ret = ret.div(&ret1);
ret.increment();
ret
}
}
impl_serializable!(BlockHeader, version, prev_blockhash, merkle_root, time, bits, nonce)
impl_serializable!(Block, header, txdata)
impl_serializable!(LoneBlockHeader, header, tx_count)
#[cfg(test)]
mod tests {
use std::io::IoResult;
use serialize::hex::FromHex;
use blockdata::block::Block;
use network::serialize::Serializable;
#[test]
fn block_test() {
let some_block = "010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b0201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d026e04ffffffff0100f2052a0100000043410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac00000000010000000321f75f3139a013f50f315b23b0c9a2b6eac31e2bec98e5891c924664889942260000000049483045022100cb2c6b346a978ab8c61b18b5e9397755cbd17d6eb2fe0083ef32e067fa6c785a02206ce44e613f31d9a6b0517e46f3db1576e9812cc98d159bfdaf759a5014081b5c01ffffffff79cda0945903627c3da1f85fc95d0b8ee3e76ae0cfdc9a65d09744b1f8fc85430000000049483045022047957cdd957cfd0becd642f6b84d82f49b6cb4c51a91f49246908af7c3cfdf4a022100e96b46621f1bffcf5ea5982f88cef651e9354f5791602369bf5a82a6cd61a62501fffffffffe09f5fe3ffbf5ee97a54eb5e5069e9da6b4856ee86fc52938c2f979b0f38e82000000004847304402204165be9a4cbab8049e1af9723b96199bfd3e85f44c6b4c0177e3962686b26073022028f638da23fc003760861ad481ead4099312c60030d4cb57820ce4d33812a5ce01ffffffff01009d966b01000000434104ea1feff861b51fe3f5f8a3b12d0f4712db80e919548a80839fc47c6a21e66d957e9c5d8cd108c7a2d2324bad71f9904ac0ae7336507d785b17a2c115e427a32fac00000000".from_hex().unwrap();
let cutoff_block = "010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b0201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d026e04ffffffff0100f2052a0100000043410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac00000000010000000321f75f3139a013f50f315b23b0c9a2b6eac31e2bec98e5891c924664889942260000000049483045022100cb2c6b346a978ab8c61b18b5e9397755cbd17d6eb2fe0083ef32e067fa6c785a02206ce44e613f31d9a6b0517e46f3db1576e9812cc98d159bfdaf759a5014081b5c01ffffffff79cda0945903627c3da1f85fc95d0b8ee3e76ae0cfdc9a65d09744b1f8fc85430000000049483045022047957cdd957cfd0becd642f6b84d82f49b6cb4c51a91f49246908af7c3cfdf4a022100e96b46621f1bffcf5ea5982f88cef651e9354f5791602369bf5a82a6cd61a62501fffffffffe09f5fe3ffbf5ee97a54eb5e5069e9da6b4856ee86fc52938c2f979b0f38e82000000004847304402204165be9a4cbab8049e1af9723b96199bfd3e85f44c6b4c0177e3962686b26073022028f638da23fc003760861ad481ead4099312c60030d4cb57820ce4d33812a5ce01ffffffff01009d966b01000000434104ea1feff861b51fe3f5f8a3b12d0f4712db80e919548a80839fc47c6a21e66d957e9c5d8cd108c7a2d2324bad71f9904ac0ae7336507d785b17a2c115e427a32fac".from_hex().unwrap();
let prevhash = "4ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000".from_hex().unwrap();
let merkle = "bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914c".from_hex().unwrap();
let decode: IoResult<Block> = Serializable::deserialize(some_block.iter().map(|n| *n));
let bad_decode: IoResult<Block> = Serializable::deserialize(cutoff_block.iter().map(|n| *n));
assert!(decode.is_ok());
assert!(bad_decode.is_err());
let real_decode = decode.unwrap();
assert_eq!(real_decode.header.version, 1);
assert_eq!(real_decode.header.prev_blockhash.as_slice(), prevhash.as_slice());
// [test] TODO: actually compute the merkle root
assert_eq!(real_decode.header.merkle_root.as_slice(), merkle.as_slice());
assert_eq!(real_decode.header.time, 1231965655);
assert_eq!(real_decode.header.bits, 486604799);
assert_eq!(real_decode.header.nonce, 2067413810);
// [test] TODO: check the transaction data
let reserialize = real_decode.serialize();
assert_eq!(reserialize.as_slice(), some_block.as_slice());
}
}

624
src/blockdata/blockchain.rs Normal file
View File

@ -0,0 +1,624 @@
// 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/>.
//
//! # Bitcoin Blockchain
//!
//! This module provides the structures and functions to maintain the
//! blockchain.
//!
//! Note to developers: do not expose any ref-counted pointers in the public
//! API of this module. Internally we do unsafe mutations of them and we need
//! to make sure we are holding the only references.
//!
use alloc::rc::Rc;
use std::cell::{Ref, RefCell};
use std::io::{IoResult, IoError, OtherIoError};
use std::num::Zero;
use std::kinds::marker;
use blockdata::block::{Block, BlockHeader};
use blockdata::transaction::Transaction;
use blockdata::constants::{DIFFCHANGE_INTERVAL, DIFFCHANGE_TIMESPAN, max_target};
use network::serialize::{Serializable, SerializeIter};
use util::BitArray;
use util::uint::Uint256;
use util::hash::Sha256dHash;
use util::misc::prepend_err;
use util::patricia_tree::PatriciaTree;
type BlockTree = PatriciaTree<Rc<BlockchainNode>, Uint256>;
type NodePtr = Option<Rc<BlockchainNode>>;
/// A link in the blockchain
pub struct BlockchainNode {
/// The actual block
pub block: Block,
/// Total work from genesis to this point
pub total_work: Uint256,
/// Expected value of `block.header.bits` for this block; only changes every
/// `blockdata::constants::DIFFCHANGE_INTERVAL;` blocks
pub required_difficulty: Uint256,
/// Height above genesis
pub height: u32,
/// Whether the transaction data is stored
pub has_txdata: bool,
/// Pointer to block's parent
prev: RefCell<NodePtr>,
/// Pointer to block's child
next: RefCell<NodePtr>
}
impl BlockchainNode {
/// Look up the previous link, caching the result
fn prev(&self, tree: &BlockTree) -> NodePtr {
let mut cache = self.prev.borrow_mut();
if cache.is_some() {
return Some(cache.get_ref().clone())
}
match tree.lookup(&self.block.header.prev_blockhash.as_uint256(), 256) {
Some(prev) => { *cache = Some(prev.clone()); return Some(prev.clone()); }
None => { return None; }
}
}
/// Look up the next link
fn next<'a>(&'a self) -> Ref<'a, NodePtr> {
self.next.borrow()
}
/// Set the next link
fn set_next(&self, next: Rc<BlockchainNode>) {
let mut cache = self.next.borrow_mut();
*cache = Some(next);
}
/// Is the node on the main chain?
fn is_on_main_chain(&self, chain: &Blockchain) -> bool {
if self.block.header == chain.best_tip.block.header {
return true;
}
let mut scan = self.next().clone();
while scan.is_some() {
if scan.get_ref().block.header == chain.best_tip.block.header {
return true;
}
scan = scan.get_ref().next().clone();
}
return false;
}
}
impl Serializable for Rc<BlockchainNode> {
fn serialize(&self) -> Vec<u8> {
let mut ret = vec![];
ret.extend(self.block.serialize().move_iter());
ret.extend(self.total_work.serialize().move_iter());
ret.extend(self.required_difficulty.serialize().move_iter());
ret.extend(self.height.serialize().move_iter());
ret.extend(self.has_txdata.serialize().move_iter());
// Don't serialize the prev pointer
ret
}
fn deserialize<I: Iterator<u8>>(mut iter: I) -> IoResult<Rc<BlockchainNode>> {
Ok(Rc::new(BlockchainNode {
block: try!(prepend_err("block", Serializable::deserialize(iter.by_ref()))),
total_work: try!(prepend_err("total_work", Serializable::deserialize(iter.by_ref()))),
required_difficulty: try!(prepend_err("req_difficulty", Serializable::deserialize(iter.by_ref()))),
height: try!(prepend_err("height", Serializable::deserialize(iter.by_ref()))),
has_txdata: try!(prepend_err("has_txdata", Serializable::deserialize(iter.by_ref()))),
prev: RefCell::new(None),
next: RefCell::new(None)
}))
}
// Override Serialize::hash to return the blockheader hash, since the
// hash of the node itself is pretty much meaningless.
fn hash(&self) -> Sha256dHash {
self.block.header.hash()
}
}
/// The blockchain
pub struct Blockchain {
tree: BlockTree,
best_tip: Rc<BlockchainNode>,
best_hash: Sha256dHash,
genesis_hash: Sha256dHash
}
impl Serializable for Blockchain {
fn serialize(&self) -> Vec<u8> {
let mut ret = vec![];
ret.extend(self.tree.serialize().move_iter());
ret.extend(self.best_hash.serialize().move_iter());
ret.extend(self.genesis_hash.serialize().move_iter());
ret
}
fn serialize_iter<'a>(&'a self) -> SerializeIter<'a> {
SerializeIter {
data_iter: None,
sub_iter_iter: box vec![ &self.tree as &Serializable,
&self.best_hash as &Serializable,
&self.genesis_hash as &Serializable ].move_iter(),
sub_iter: None,
sub_started: false
}
}
fn deserialize<I: Iterator<u8>>(mut iter: I) -> IoResult<Blockchain> {
let tree: BlockTree = try!(prepend_err("tree", Serializable::deserialize(iter.by_ref())));
let best_hash: Sha256dHash = try!(prepend_err("best_hash", Serializable::deserialize(iter.by_ref())));
let genesis_hash: Sha256dHash = try!(prepend_err("genesis_hash", Serializable::deserialize(iter.by_ref())));
// Lookup best tip
let best = match tree.lookup(&best_hash.as_uint256(), 256) {
Some(rc) => rc.clone(),
None => { return Err(IoError {
kind: OtherIoError,
desc: "best tip reference not found in tree",
detail: Some(format!("best tip {:x} not found", best_hash))
});
}
};
// Lookup genesis
if tree.lookup(&genesis_hash.as_uint256(), 256).is_none() {
return Err(IoError {
kind: OtherIoError,
desc: "genesis block not found in tree",
detail: Some(format!("genesis {:x} not found", genesis_hash))
});
}
// Reconnect next and prev pointers back to "genesis", the first node
// with no prev pointer.
let mut scan = best.clone();
let mut prev = best.prev(&tree);
while prev.is_some() {
prev.get_mut_ref().set_next(scan);
scan = prev.get_ref().clone();
prev = prev.get_ref().prev(&tree);
}
// Check that "genesis" is the genesis
if scan.block.header.hash() != genesis_hash {
Err(IoError {
kind: OtherIoError,
desc: "best tip did not link back to genesis",
detail: Some(format!("no path from tip {:x} to genesis {:x}", best_hash, genesis_hash))
})
} else {
// Return the chain
Ok(Blockchain {
tree: tree,
best_tip: best.clone(),
best_hash: best_hash,
genesis_hash: genesis_hash
})
}
}
}
struct LocatorHashIter<'tree> {
index: NodePtr,
tree: &'tree BlockTree,
count: uint,
skip: uint
}
impl<'tree> LocatorHashIter<'tree> {
fn new<'tree>(init: Rc<BlockchainNode>, tree: &'tree BlockTree) -> LocatorHashIter<'tree> {
LocatorHashIter { index: Some(init), tree: tree, count: 0, skip: 1 }
}
}
impl<'tree> Iterator<Sha256dHash> for LocatorHashIter<'tree> {
fn next(&mut self) -> Option<Sha256dHash> {
let ret = match self.index {
Some(ref node) => Some(node.hash()),
None => { return None; }
};
// Rewind once (if we are at the genesis, this will set self.index to None)
self.index = self.index.get_ref().prev(self.tree);
// If we are not at the genesis, rewind `self.skip` times, or until we are.
if self.index.is_some() {
for _ in range(1, self.skip) {
self.index = match self.index.get_ref().prev(self.tree) {
Some(rc) => Some(rc),
None => { break; }
}
}
}
self.count += 1;
if self.count > 10 {
self.skip *= 2;
}
ret
}
}
/// An iterator over blocks in blockheight order
pub struct BlockIter<'tree> {
index: NodePtr,
// Note: we don't actually touch the blockchain. But we need
// to keep it borrowed to prevent it being mutated, since some
// mutable blockchain methods call .mut_borrow() on the block
// links, which would blow up if the iterator did a regular
// borrow at the same time.
marker: marker::ContravariantLifetime<'tree>
}
/// An iterator over blocks in reverse blockheight order. Note that this
/// is essentially the same as if we'd implemented `DoubleEndedIterator`
/// on `BlockIter` --- but we can't do that since if `BlockIter` is started
/// off the main chain, it will not reach the best tip, so the iterator
/// and its `.rev()` would be iterators over different chains! To avoid
/// this suprising behaviour we simply use separate iterators.
pub struct RevBlockIter<'tree> {
index: NodePtr,
tree: &'tree BlockTree
}
/// An iterator over blocks in reverse blockheight order, which yielding only
/// stale blocks (ending at the point where it would've returned a block on
/// the main chain). It does this by checking if the `next` pointer of the
/// next-to-by-yielded block matches the currently-yielded block. If not, scan
/// forward from next-to-be-yielded block. If we hit the best tip, set the
/// next-to-by-yielded block to None instead.
///
/// So to handle reorgs, you create a `RevStaleBlockIter` starting from the last
/// known block, and play it until it runs out, rewinding every block except for
/// the last one. Since the UtxoSet `rewind` function sets its `last_hash()` to
/// the prevblockhash of the rewinded block (which will be on the main chain at
/// the end of the iteration), you can then sync it up same as if you were doing
/// a plain old fast-forward.
pub struct RevStaleBlockIter<'tree> {
index: NodePtr,
chain: &'tree Blockchain
}
impl<'tree> Iterator<&'tree BlockchainNode> for BlockIter<'tree> {
fn next(&mut self) -> Option<&'tree BlockchainNode> {
match self.index.clone() {
Some(rc) => {
use core::mem::transmute;
self.index = rc.next().clone();
// This transmute is just to extend the lifetime of rc.block
// There is unsafety here because we need to be assured that
// another copy of the rc (presumably the one in the tree)
// exists and will live as long as 'tree.
Some(unsafe { transmute(&*rc) } )
},
None => None
}
}
}
impl<'tree> Iterator<&'tree BlockchainNode> for RevBlockIter<'tree> {
fn next(&mut self) -> Option<&'tree BlockchainNode> {
match self.index.clone() {
Some(rc) => {
use core::mem::transmute;
self.index = rc.prev(self.tree).clone();
// This transmute is just to extend the lifetime of rc.block
// There is unsafety here because we need to be assured that
// another copy of the rc (presumably the one in the tree)
// exists and will live as long as 'tree.
Some(unsafe { transmute(&*rc) } )
},
None => None
}
}
}
impl<'tree> Iterator<&'tree Block> for RevStaleBlockIter<'tree> {
fn next(&mut self) -> Option<&'tree Block> {
match self.index.clone() {
Some(rc) => {
use core::mem::transmute;
let next_index = rc.prev(&self.chain.tree);
// Check if the next block is going to be on the main chain
if next_index.is_some() &&
next_index.get_ref().next().get_ref().block.header != rc.block.header &&
next_index.get_ref().is_on_main_chain(self.chain) {
self.index = None;
} else {
self.index = next_index.clone();
}
// This transmute is just to extend the lifetime of rc.block
// There is unsafety here because we need to be assured that
// another copy of the rc (presumably the one in the tree)
// exists and will live as long as 'tree.
Some(unsafe { transmute(&rc.block) } )
},
None => None
}
}
}
/// This function emulates the GetCompact(SetCompact(n)) in the satoshi code,
/// which drops the precision to something that can be encoded precisely in
/// the nBits block header field. Savour the perversity. This is in Bitcoin
/// consensus code. What. The. Fuck.
fn satoshi_the_precision(n: &Uint256) -> Uint256 {
// Shift by B bits right then left to turn the low bits to zero
let bits = 8 * ((n.bits() + 7) / 8 - 3);
let mut ret = n >> bits;
// Oh, did I say B was that fucked up formula? I meant sometimes also + 8.
if ret.bit(23) {
ret = (ret >> 8) << 8;
}
ret << bits
}
impl Blockchain {
/// Constructs a new blockchain
pub fn new(genesis: Block) -> Blockchain {
let genhash = genesis.header.hash();
let rc_gen = Rc::new(BlockchainNode {
total_work: Zero::zero(),
required_difficulty: genesis.header.target(),
block: genesis,
height: 0,
has_txdata: true,
prev: RefCell::new(None),
next: RefCell::new(None)
});
Blockchain {
tree: {
let mut pat = PatriciaTree::new();
pat.insert(&genhash.as_uint256(), 256, rc_gen.clone());
pat
},
best_hash: genhash,
genesis_hash: genhash,
best_tip: rc_gen,
}
}
fn replace_txdata(&mut self, hash: &Uint256, txdata: Vec<Transaction>, has_txdata: bool) -> bool {
match self.tree.lookup_mut(hash, 256) {
Some(existing_block) => {
unsafe {
// existing_block is an Rc. Rust will not let us mutate it under
// any circumstances, since if it were to be reallocated, then
// all other references to it would be destroyed. However, we
// just need a mutable pointer to the txdata vector; by calling
// Vec::clone_from() rather than assigning, we can be assured that
// no reallocation can occur, since clone_from() takes an &mut self,
// which it does not own and therefore cannot move.
//
// To be clear: there will undoubtedly be some reallocation within
// the Vec itself. We don't care about this. What we care about is
// that the Vec (and more pointedly, its containing struct) does not
// move, since this would invalidate the Rc that we are snookering.
use std::mem::{forget, transmute};
let mutable_vec: &mut Vec<Transaction> = transmute(&existing_block.block.txdata);
mutable_vec.clone_from(&txdata);
// If mutable_vec went out of scope unhindered, it would deallocate
// the Vec it points to, since Rust assumes that a mutable vector
// is a unique reference (and this one is definitely not).
forget(mutable_vec);
// Do the same thing with the txdata flac
let mutable_bool: &mut bool = transmute(&existing_block.has_txdata);
*mutable_bool = has_txdata;
forget(mutable_bool);
}
return true
},
None => return false
}
}
/// Locates a block in the chain and overwrites its txdata
pub fn add_txdata(&mut self, block: Block) -> bool {
self.replace_txdata(&block.header.hash().as_uint256(), block.txdata, true)
}
/// Locates a block in the chain and removes its txdata
pub fn remove_txdata(&mut self, hash: Sha256dHash) -> bool {
self.replace_txdata(&hash.as_uint256(), vec![], false)
}
/// Adds a block header to the chain
pub fn add_header(&mut self, header: BlockHeader) -> bool {
self.real_add_block(Block { header: header, txdata: vec![] }, false)
}
/// Adds a block to the chain
pub fn add_block(&mut self, block: Block) -> bool {
self.real_add_block(block, true)
}
fn real_add_block(&mut self, block: Block, has_txdata: bool) -> bool {
// get_prev optimizes the common case where we are extending the best tip
fn get_prev<'a>(chain: &'a Blockchain, hash: Sha256dHash) -> Option<&'a Rc<BlockchainNode>> {
if hash == chain.best_hash { return Some(&chain.best_tip); }
chain.tree.lookup(&hash.as_uint256(), 256)
}
// Check for multiple inserts (bitcoind from c9a09183 to 3c85d2ec doesn't
// handle locator hashes properly and may return blocks multiple times,
// and this may also happen in case of a reorg.
if self.tree.lookup(&block.header.hash().as_uint256(), 256).is_some() {
println!("Warning: tried to add block {} twice!", block.header.hash());
return true;
}
// Construct node, if possible
let rc_block = match get_prev(self, block.header.prev_blockhash) {
Some(prev) => {
let difficulty =
// Compute required difficulty if this is a diffchange block
if (prev.height + 1) % DIFFCHANGE_INTERVAL == 0 {
// Scan back DIFFCHANGE_INTERVAL blocks
let mut scan = prev.clone();
for _ in range(0, DIFFCHANGE_INTERVAL - 1) {
scan = scan.prev(&self.tree).unwrap();
}
// Get clamped timespan between first and last blocks
let timespan = match prev.block.header.time - scan.block.header.time {
n if n < DIFFCHANGE_TIMESPAN / 4 => DIFFCHANGE_TIMESPAN / 4,
n if n > DIFFCHANGE_TIMESPAN * 4 => DIFFCHANGE_TIMESPAN * 4,
n => n
};
// Compute new target
let mut target = prev.block.header.target();
target = target.mul_u32(timespan);
target = target / FromPrimitive::from_u64(DIFFCHANGE_TIMESPAN as u64).unwrap();
// Clamp below MAX_TARGET (difficulty 1)
let max = max_target();
if target > max { target = max };
// Compactify (make expressible in the 8+24 nBits float format
satoshi_the_precision(&target)
} else {
// Otherwise just use the last block's difficulty
prev.required_difficulty
};
// Create node
let ret = Rc::new(BlockchainNode {
total_work: block.header.work().add(&prev.total_work),
block: block,
required_difficulty: difficulty,
height: prev.height + 1,
has_txdata: has_txdata,
prev: RefCell::new(Some(prev.clone())),
next: RefCell::new(None)
});
prev.set_next(ret.clone());
ret
},
None => {
println!("TODO: couldn't add block");
return false;
}
};
// spv validate the block
if !rc_block.block.header.spv_validate(&rc_block.required_difficulty) {
return false;
}
// Insert the new block
self.tree.insert(&rc_block.block.header.hash().as_uint256(), 256, rc_block.clone());
// Replace the best tip if necessary
if rc_block.total_work > self.best_tip.total_work {
self.set_best_tip(rc_block);
}
return true;
}
/// Sets the best tip (not public)
fn set_best_tip(&mut self, tip: Rc<BlockchainNode>) {
let old_best = self.best_tip.clone();
// Set best
self.best_hash = tip.hash();
self.best_tip = tip;
// Fix next links
let mut scan = self.best_tip.clone();
let mut prev = self.best_tip.prev(&self.tree);
// Scan backward
loop {
// If we hit the old best, there is no need to reorg
if scan.block.header == old_best.block.header {
break;
}
// If we hit the genesis, stop
if prev.is_none() {
println!("Warning: reorg past the genesis. This is a bug.");
break;
}
// If we hit something pointing along the wrong chain, this is
// a branch point at which we are reorg'ing
if prev.get_ref().next().is_none() ||
prev.get_ref().next().get_ref().block.header != scan.block.header {
prev.get_mut_ref().set_next(scan);
}
scan = prev.clone().unwrap();
prev = prev.unwrap().prev(&self.tree);
}
}
/// Returns the best tip
pub fn best_tip<'a>(&'a self) -> &'a Block {
&self.best_tip.block
}
/// Returns the best tip's blockhash
pub fn best_tip_hash(&self) -> Sha256dHash {
self.best_hash
}
/// Returns an array of locator hashes used in `getheaders` messages
pub fn locator_hashes(&self) -> Vec<Sha256dHash> {
LocatorHashIter::new(self.best_tip.clone(), &self.tree).collect()
}
/// An iterator over all blocks in the chain starting from `start_hash`
pub fn iter<'a>(&'a self, start_hash: Sha256dHash) -> BlockIter<'a> {
BlockIter {
index: self.tree.lookup(&start_hash.as_uint256(), 256).map(|rc| rc.clone()),
marker: marker::ContravariantLifetime::<'a>
}
}
/// An iterator over all blocks in reverse order to the genesis, starting with `start_hash`
pub fn rev_iter<'a>(&'a self, start_hash: Sha256dHash) -> RevBlockIter<'a> {
RevBlockIter {
index: self.tree.lookup(&start_hash.as_uint256(), 256).map(|rc| rc.clone()),
tree: &self.tree
}
}
/// An iterator over all blocks -not- in the best chain, in reverse order, starting from `start_hash`
pub fn rev_stale_iter<'a>(&'a self, start_hash: Sha256dHash) -> RevStaleBlockIter<'a> {
let mut start = self.tree.lookup(&start_hash.as_uint256(), 256).map(|rc| rc.clone());
// If we are already on the main chain, we have a dead iterator
if start.is_some() && start.get_ref().is_on_main_chain(self) {
start = None;
}
// Return iterator
RevStaleBlockIter {
index: start,
chain: self
}
}
}
#[cfg(test)]
mod tests {
use std::prelude::*;
use std::io::IoResult;
use blockdata::blockchain::Blockchain;
use blockdata::constants::genesis_block;
use network::serialize::Serializable;
#[test]
fn blockchain_serialize_test() {
let empty_chain = Blockchain::new(genesis_block());
assert_eq!(empty_chain.best_tip.hash().serialize(), genesis_block().header.hash().serialize());
let serial = empty_chain.serialize();
assert_eq!(serial, empty_chain.serialize_iter().collect());
let deserial: IoResult<Blockchain> = Serializable::deserialize(serial.iter().map(|n| *n));
assert!(deserial.is_ok());
let read_chain = deserial.unwrap();
assert_eq!(read_chain.best_tip.hash().serialize(), genesis_block().header.hash().serialize());
}
}

140
src/blockdata/constants.rs Normal file
View File

@ -0,0 +1,140 @@
// 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/>.
//
//! # Blockdata constants
//!
//! This module provides various constants relating to the blockchain and
//! consensus code. In particular, it defines the genesis block and its
//! single transaction
//!
use std::num::from_u64;
use blockdata::opcodes;
use blockdata::script::Script;
use blockdata::transaction::{Transaction, TxOut, TxIn};
use blockdata::block::{Block, BlockHeader};
use util::misc::hex_bytes;
use util::hash::{merkle_root, zero_hash};
use util::uint::Uint256;
pub static MAX_SEQUENCE: u32 = 0xFFFFFFFF;
pub static COIN_VALUE: u64 = 100000000;
pub static DIFFCHANGE_INTERVAL: u32 = 2016;
pub static DIFFCHANGE_TIMESPAN: u32 = 14 * 24 * 3600;
/// In Bitcoind this is insanely described as ~((u256)0 >> 32)
pub fn max_target() -> Uint256 {
from_u64::<Uint256>(0xFFFF).unwrap() << 208u
}
/// Constructs and returns the coinbase (and only) transaction of the genesis block
pub fn genesis_tx() -> Transaction {
// Base
let mut ret = Transaction {
version: 1,
lock_time: 0,
input: vec![],
output: vec![]
};
// Inputs
let mut in_script = Script::new();
in_script.push_scriptint(486604799);
in_script.push_scriptint(4);
in_script.push_slice("The Times 03/Jan/2009 Chancellor on brink of second bailout for banks".as_bytes());
ret.input.push(TxIn {
prev_hash: zero_hash(),
prev_index: 0xFFFFFFFF,
script_sig: in_script,
sequence: MAX_SEQUENCE
});
// Outputs
let mut out_script = Script::new();
out_script.push_slice(hex_bytes("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f").unwrap().as_slice());
out_script.push_opcode(opcodes::CHECKSIG);
ret.output.push(TxOut {
value: 50 * COIN_VALUE,
script_pubkey: out_script
});
// end
ret
}
/// Constructs and returns the genesis block
pub fn genesis_block() -> Block {
let txdata = vec![genesis_tx()];
let header = BlockHeader {
version: 1,
prev_blockhash: zero_hash(),
merkle_root: merkle_root(txdata.as_slice()),
time: 1231006505,
bits: 0x1d00ffff,
nonce: 2083236893
};
Block {
header: header,
txdata: txdata
}
}
#[cfg(test)]
mod test {
use network::serialize::Serializable;
use blockdata::constants::{genesis_block, genesis_tx};
use blockdata::constants::{MAX_SEQUENCE, COIN_VALUE};
use util::misc::hex_bytes;
use util::hash::zero_hash;
#[test]
fn genesis_first_transaction() {
let gen = genesis_tx();
assert_eq!(gen.version, 1);
assert_eq!(gen.input.len(), 1);
assert_eq!(gen.input[0].prev_hash.as_slice(), zero_hash().as_slice());
assert_eq!(gen.input[0].prev_index, 0xFFFFFFFF);
assert_eq!(gen.input[0].script_sig.serialize().as_slice(),
hex_bytes("4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73").unwrap().as_slice());
assert_eq!(gen.input[0].sequence, MAX_SEQUENCE);
assert_eq!(gen.output.len(), 1);
assert_eq!(gen.output[0].script_pubkey.serialize().as_slice(),
hex_bytes("434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac").unwrap().as_slice());
assert_eq!(gen.output[0].value, 50 * COIN_VALUE);
assert_eq!(gen.lock_time, 0);
assert_eq!(gen.hash().serialize().iter().rev().map(|n| *n).collect::<Vec<u8>>(),
hex_bytes("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b").unwrap());
}
#[test]
fn genesis_full_block() {
let gen = genesis_block();
assert_eq!(gen.header.version, 1);
assert_eq!(gen.header.prev_blockhash.as_slice(), zero_hash().as_slice());
assert_eq!(gen.header.merkle_root.serialize().iter().rev().map(|n| *n).collect::<Vec<u8>>(),
hex_bytes("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b").unwrap());
assert_eq!(gen.header.time, 1231006505);
assert_eq!(gen.header.bits, 0x1d00ffff);
assert_eq!(gen.header.nonce, 2083236893);
assert_eq!(gen.header.hash().serialize().iter().rev().map(|n| *n).collect::<Vec<u8>>(),
hex_bytes("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f").unwrap());
}
}

29
src/blockdata/mod.rs Normal file
View File

@ -0,0 +1,29 @@
// 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/>.
//
//! # Blockdata
//!
//! This module defines structions and functions for storing the blocks and
//! transactions which make up the Bitcoin system.
//!
pub mod constants;
pub mod opcodes;
pub mod script;
pub mod transaction;
pub mod block;
pub mod blockchain;
pub mod utxoset;

28
src/blockdata/opcodes.rs Normal file
View File

@ -0,0 +1,28 @@
// 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/>.
//
//! # Opcodes
//!
//! Bitcoin's script uses a stack-based assembly language. This module defines
//! the mapping from assembler instructions to bytes.
//!
pub static FALSE: u8 = 0x00;
pub static TRUE: u8 = 0x51;
pub static PUSHDATA1: u8 = 0x4C;
pub static PUSHDATA2: u8 = 0x4D;
pub static PUSHDATA4: u8 = 0x4E;
pub static CHECKSIG: u8 = 0xAC;

181
src/blockdata/script.rs Normal file
View File

@ -0,0 +1,181 @@
// 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/>.
//
//! # Script
//!
//! Scripts define Bitcoin's digital signature scheme: a signature is formed
//! from a script (the second half of which is defined by a coin to be spent,
//! and the first half provided by the spending transaction), and is valid
//! iff the script leaves `TRUE` on the stack after being evaluated.
//! Bitcoin's script is a stack-based assembly language similar in spirit to
//! Forth.
//!
//! This module provides the structures and functions needed to support scripts.
//!
use std::io::IoResult;
use network::serialize::Serializable;
use blockdata::opcodes;
use util::thinvec::ThinVec;
#[deriving(PartialEq, Show, Clone)]
/// A Bitcoin script
pub struct Script(ThinVec<u8>);
impl Script {
/// Creates a new empty script
pub fn new() -> Script { Script(ThinVec::new()) }
/// Adds instructions to push an integer onto the stack. Integers are
/// encoded as little-endian signed-magnitude numbers, but there are
/// dedicated opcodes to push some small integers.
pub fn push_int(&mut self, data: int) {
// We can special-case -1, 1-16
if data == -1 || (data >= 1 && data <=16) {
let &Script(ref mut raw) = self;
raw.push(data as u8 + opcodes::TRUE);
return;
}
// We can also special-case zero
if data == 0 {
let &Script(ref mut raw) = self;
raw.push(opcodes::FALSE);
return;
}
// Otherwise encode it as data
self.push_scriptint(data);
}
/// Adds instructions to push an integer onto the stack, using the explicit
/// encoding regardless of the availability of dedicated opcodes.
pub fn push_scriptint(&mut self, data: int) {
let neg = data < 0;
let mut abs = if neg { -data } else { data } as uint;
let mut v = vec![];
while abs > 0xFF {
v.push((abs & 0xFF) as u8);
abs >>= 8;
}
// If the number's value causes the sign bit to be set, we need an extra
// byte to get the correct value and correct sign bit
if abs & 0x80 != 0 {
v.push(abs as u8);
v.push(if neg { 0x80u8 } else { 0u8 });
}
// Otherwise we just set the sign bit ourselves
else {
abs |= if neg { 0x80 } else { 0 };
v.push(abs as u8);
}
// Finally we put the encoded int onto the stack
self.push_slice(v.as_slice());
}
/// Adds instructions to push some arbitrary data onto the stack
pub fn push_slice(&mut self, data: &[u8]) {
let &Script(ref mut raw) = self;
// Start with a PUSH opcode
match data.len() {
n if n < opcodes::PUSHDATA1 as uint => { raw.push(n as u8); },
n if n < 0x100 => {
raw.push(opcodes::PUSHDATA1);
raw.push(n as u8);
},
n if n < 0x10000 => {
raw.push(opcodes::PUSHDATA2);
raw.push((n % 0x100) as u8);
raw.push((n / 0x100) as u8);
},
n if n < 0x100000000 => {
raw.push(opcodes::PUSHDATA4);
raw.push((n % 0x100) as u8);
raw.push(((n / 0x100) % 0x100) as u8);
raw.push(((n / 0x10000) % 0x100) as u8);
raw.push((n / 0x1000000) as u8);
}
_ => fail!("tried to put a 4bn+ sized object into a script!")
}
// Then push the acraw
raw.extend(data.iter().map(|n| *n));
}
/// Adds an individual opcode to the script
pub fn push_opcode(&mut self, data: u8) {
let &Script(ref mut raw) = self;
raw.push(data);
}
}
impl Serializable for Script {
fn serialize(&self) -> Vec<u8> {
let &Script(ref data) = self;
data.serialize()
}
fn deserialize<I: Iterator<u8>>(iter: I) -> IoResult<Script> {
let raw = Serializable::deserialize(iter);
raw.map(|ok| Script(ok))
}
}
#[cfg(test)]
mod test {
use std::io::IoResult;
use network::serialize::Serializable;
use blockdata::script::Script;
use blockdata::opcodes;
use util::misc::hex_bytes;
use util::thinvec::ThinVec;
#[test]
fn script() {
let mut comp = ThinVec::new();
let mut script = Script::new();
assert_eq!(script, Script(ThinVec::new()));
// small ints
script.push_int(1); comp.push(82u8); assert_eq!(script, Script(comp.clone()));
script.push_int(0); comp.push(0u8); assert_eq!(script, Script(comp.clone()));
script.push_int(4); comp.push(85u8); assert_eq!(script, Script(comp.clone()));
script.push_int(-1); comp.push(80u8); assert_eq!(script, Script(comp.clone()));
// forced scriptint
script.push_scriptint(4); comp.push_all([1u8, 4]); assert_eq!(script, Script(comp.clone()));
// big ints
script.push_int(17); comp.push_all([1u8, 17]); assert_eq!(script, Script(comp.clone()));
script.push_int(10000); comp.push_all([2u8, 16, 39]); assert_eq!(script, Script(comp.clone()));
// notice the sign bit set here, hence the extra zero/128 at the end
script.push_int(10000000); comp.push_all([4u8, 128, 150, 152, 0]); assert_eq!(script, Script(comp.clone()));
script.push_int(-10000000); comp.push_all([4u8, 128, 150, 152, 128]); assert_eq!(script, Script(comp.clone()));
// data
script.push_slice("NRA4VR".as_bytes()); comp.push_all([6u8, 78, 82, 65, 52, 86, 82]); assert_eq!(script, Script(comp.clone()));
// opcodes
script.push_opcode(opcodes::CHECKSIG); comp.push(0xACu8); assert_eq!(script, Script(comp.clone()));
script.push_opcode(opcodes::CHECKSIG); comp.push(0xACu8); assert_eq!(script, Script(comp.clone()));
}
#[test]
fn script_serialize() {
let hex_script = hex_bytes("6c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52").unwrap();
let script: IoResult<Script> = Serializable::deserialize(hex_script.iter().map(|n| *n));
assert!(script.is_ok());
assert_eq!(script.unwrap().serialize().as_slice(), hex_script.as_slice());
}
}

View File

@ -0,0 +1,107 @@
// 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/>.
//
//! # Bitcoin Transaction
//!
//! A transaction describes a transfer of money. It consumes previously-unspent
//! transaction outputs and produces new ones, satisfying the condition to spend
//! the old outputs (typically a digital signature with a specific key must be
//! provided) and defining the condition to spend the new ones. The use of digital
//! signatures ensures that coins cannot be spent by unauthorized parties.
//!
//! This module provides the structures and functions needed to support transactions.
//!
use std::io::IoResult;
use util::hash::Sha256dHash;
use network::serialize::{Serializable, SerializeIter};
use blockdata::script::Script;
#[cfg(test)]
use util::misc::hex_bytes;
/// A transaction input, which defines old coins to be consumed
#[deriving(Clone, PartialEq, Show)]
pub struct TxIn {
/// The hash of the transaction whose output is being used an an input
pub prev_hash: Sha256dHash,
/// The index of the output in the previous transaction, which may have several
pub prev_index: u32,
/// The script which pushes values on the stack which will cause
/// the referenced output's script to accept
pub script_sig: Script,
/// The sequence number, which suggests to miners which of two
/// conflicting transactions should be preferred, or 0xFFFFFFFF
/// to ignore this feature. This is generally never used since
/// the miner behaviour cannot be enforced.
pub sequence: u32,
}
/// A transaction output, which defines new coins to be created from old ones.
#[deriving(Clone, PartialEq, Show)]
pub struct TxOut {
/// The value of the output, in satoshis
pub value: u64,
/// The script which must satisfy for the output to be spent
pub script_pubkey: Script
}
/// A Bitcoin transaction, which describes an authenticated movement of coins
#[deriving(Clone, PartialEq, Show)]
pub struct Transaction {
/// The protocol version, should always be 1.
pub version: u32,
/// Block number before which this transaction is valid, or 0 for
/// valid immediately.
pub lock_time: u32,
/// List of inputs
pub input: Vec<TxIn>,
/// List of outputs
pub output: Vec<TxOut>
}
impl_serializable!(TxIn, prev_hash, prev_index, script_sig, sequence)
impl_serializable!(TxOut, value, script_pubkey)
impl_serializable!(Transaction, version, input, output, lock_time)
#[test]
fn test_txin() {
let txin: IoResult<TxIn> = Serializable::deserialize(hex_bytes("a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff").unwrap().iter().map(|n| *n));
assert!(txin.is_ok());
}
#[test]
fn test_transaction() {
let hex_tx = hex_bytes("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap();
let tx: IoResult<Transaction> = Serializable::deserialize(hex_tx.iter().map(|n| *n));
assert!(tx.is_ok());
let realtx = tx.unwrap();
// All these tests aren't really needed because if they fail, the hash check at the end
// will also fail. But these will show you where the failure is so I'll leave them in.
assert_eq!(realtx.version, 1);
assert_eq!(realtx.input.len(), 1);
// In particular this one is easy to get backward -- in bitcoin hashes are encoded
// as little-endian 256-bit numbers rather than as data strings. (This is why we
// have this crazy .iter().rev() thing going on in many hash-related tests.
assert_eq!(realtx.input[0].prev_hash.as_slice().iter().rev().map(|n| *n).collect::<Vec<u8>>(),
hex_bytes("ce9ea9f6f5e422c6a9dbcddb3b9a14d1c78fab9ab520cb281aa2a74a09575da1").unwrap());
assert_eq!(realtx.input[0].prev_index, 1);
assert_eq!(realtx.output.len(), 1);
assert_eq!(realtx.lock_time, 0);
assert_eq!(realtx.hash().serialize().iter().rev().map(|n| *n).collect::<Vec<u8>>(),
hex_bytes("a6eab3c14ab5272a58a5ba91505ba1a4b6d7a3a9fcbd187b6cd99a7b6d548cb7").unwrap());
}

356
src/blockdata/utxoset.rs Normal file
View File

@ -0,0 +1,356 @@
// 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/>.
//
//! # UTXO Set
//!
//! This module provides the structures and functions to maintain an
//! index of UTXOs.
//!
use std::io::IoResult;
use std::mem;
use blockdata::transaction::{Transaction, TxOut};
use blockdata::block::Block;
use network::serialize::{Serializable, SerializeIter};
use util::hash::Sha256dHash;
use util::uint::Uint128;
use util::patricia_tree::PatriciaTree;
use util::thinvec::ThinVec;
/// How much of the hash to use as a key
static KEY_LEN: uint = 128;
/// Vector of outputs; None indicates a nonexistent or already spent output
type UtxoNode = ThinVec<Option<Box<TxOut>>>;
/// The UTXO set
pub struct UtxoSet {
// We use a 128-bit indexed tree to save memory
tree: PatriciaTree<UtxoNode, Uint128>,
last_hash: Sha256dHash,
// A circular buffer of deleted utxos, grouped by block
spent_txos: Vec<Vec<Box<TxOut>>>,
// The last index into the above buffer that was assigned to
spent_idx: u64,
n_utxos: u64
}
impl_serializable!(UtxoSet, last_hash, n_utxos, spent_txos, spent_idx, tree)
impl UtxoSet {
/// Constructs a new UTXO set
pub fn new(genesis: Block, rewind_limit: uint) -> UtxoSet {
// There is in fact a transaction in the genesis block, but the Bitcoin
// reference client does not add its sole output to the UTXO set. We
// must follow suit, otherwise we will accept a transaction spending it
// while the reference client won't, causing us to fork off the network.
UtxoSet {
tree: PatriciaTree::new(),
last_hash: genesis.header.hash(),
spent_txos: Vec::from_elem(rewind_limit, vec![]),
spent_idx: 0,
n_utxos: 0
}
}
/// Add all the UTXOs of a transaction to the set
fn add_utxos(&mut self, tx: &Transaction) -> bool {
let txid = tx.hash();
// Locate node if it's already there
let mut new_node = ThinVec::with_capacity(tx.output.len() as u32);
for (vout, txo) in tx.output.iter().enumerate() {
// Unsafe since we are not uninitializing the old data in the vector
unsafe { new_node.init(vout as uint, Some(box txo.clone())); }
}
// TODO: insert/lookup should return a Result which we pass along
if self.tree.insert(&txid.as_uint128(), KEY_LEN, new_node) {
self.n_utxos += tx.output.len() as u64;
return true;
}
return false;
}
/// Remove a UTXO from the set and return it
fn take_utxo(&mut self, txid: Sha256dHash, vout: u32) -> Option<Box<TxOut>> {
// This whole function has awkward scoping thx to lexical borrow scoping :(
let (ret, should_delete) = {
// Locate the UTXO, failing if not found
let node = match self.tree.lookup_mut(&txid.as_uint128(), KEY_LEN) {
Some(node) => node,
None => return None
};
let ret = {
// Check that this specific output is there
if vout as uint >= node.len() { return None; }
let replace = unsafe { node.get_mut(vout as uint) };
replace.take()
};
let should_delete = node.iter().filter(|slot| slot.is_some()).count() == 0;
(ret, should_delete)
};
// Delete the whole node if it is no longer being used
if should_delete {
self.tree.delete(&txid.as_uint128(), KEY_LEN);
}
self.n_utxos -= if ret.is_some() { 1 } else { 0 };
ret
}
/// Get a reference to a UTXO in the set
pub fn get_utxo<'a>(&'a mut self, txid: Sha256dHash, vout: u32) -> Option<&'a Box<TxOut>> {
// Locate the UTXO, failing if not found
let node = match self.tree.lookup_mut(&txid.as_uint128(), KEY_LEN) {
Some(node) => node,
None => return None
};
// Check that this specific output is there
if vout as uint >= node.len() { return None; }
let replace = unsafe { node.get(vout as uint) };
replace.as_ref()
}
/// Apply the transactions contained in a block
pub fn update(&mut self, block: &Block) -> bool {
// Make sure we are extending the UTXO set in order
if self.last_hash != block.header.prev_blockhash {
return false;
}
// Set the next hash immediately so that if anything goes wrong,
// we can rewind from the point that we're at.
self.last_hash = block.header.hash();
let spent_idx = self.spent_idx as uint;
self.spent_idx = (self.spent_idx + 1) % self.spent_txos.len() as u64;
self.spent_txos.get_mut(spent_idx).clear();
let mut skipped_genesis = false;
for tx in block.txdata.iter() {
// Put the removed utxos into the stxo cache. Note that the order that
// they are pushed onto the stxo cache -must- match the order of the
// txos in the block so that rewind() will rewind them properly.
if skipped_genesis {
self.spent_txos.get_mut(spent_idx).reserve_additional(tx.input.len());
for input in tx.input.iter() {
let taken = self.take_utxo(input.prev_hash, input.prev_index);
match taken {
Some(txo) => { self.spent_txos.get_mut(spent_idx).push(txo); }
None => { self.rewind(block); }
}
}
}
skipped_genesis = true;
// Add outputs
// This will fail in the case of a duplicate transaction. This can only
// happen with coinbases, and in this case the block is invalid, -except-
// for two historic blocks which appeared in the blockchain before the
// dupes were noticed. See bitcoind commit `ab91bf39` and BIP30.
// TODO: add a unit test for these blocks.
if !self.add_utxos(tx) {
let blockhash = block.header.hash().le_hex_string();
if blockhash == "00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec".to_string() ||
blockhash == "00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721".to_string() {
// For these specific blocks, overwrite the old UTXOs.
self.tree.delete(&tx.hash().as_uint128(), KEY_LEN);
self.add_utxos(tx);
} else {
// Otherwise fail the block
self.rewind(block);
return false;
}
}
}
// If we made it here, success!
true
}
/// Unapply the transactions contained in a block
pub fn rewind(&mut self, block: &Block) -> bool {
// Make sure we are rewinding the latest block
if self.last_hash != block.header.hash() {
return false;
}
// We deliberately do no error checking here, since we may be rewinding
// from halfway through the new block addition, in which case many of
// the utxos we try to remove may be missing; the ones we try to add,
// we stored ourselves when we removed them, so they won't be unaddable
// for any reason.
// Plus we don't care too much about efficiency, not many blocks should
// get rewound.
// Delete added txouts
let mut skipped_genesis = false;
for tx in block.txdata.iter() {
let txhash = tx.hash();
for n in range(0, tx.output.len()) {
// Just bomb out the whole transaction
self.take_utxo(txhash, n as u32);
}
// Read deleted txouts -- note that we are trusting that these are
// in the same order in our cache as they were in the original block.
if skipped_genesis {
let mut extract_vec = vec![];
mem::swap(&mut extract_vec, self.spent_txos.get_mut(self.spent_idx as uint));
for (txo, inp) in extract_vec.move_iter().zip(tx.input.iter()) {
// Remove the tx's utxo list and patch the txo into place
let new_node =
match self.tree.delete(&inp.prev_hash.as_uint128(), KEY_LEN) {
Some(mut thinvec) => {
let old_len = thinvec.len() as u32;
if old_len < inp.prev_index + 1 {
thinvec.reserve(inp.prev_index + 1);
for i in range(old_len, inp.prev_index + 1) {
unsafe { thinvec.init(i as uint, None); }
}
}
unsafe { *thinvec.get_mut(inp.prev_index as uint) = Some(txo); }
thinvec
}
None => {
let mut thinvec = ThinVec::with_capacity(inp.prev_index + 1);
for i in range(0, inp.prev_index + 1) {
unsafe { thinvec.init(i as uint, None); }
}
unsafe { *thinvec.get_mut(inp.prev_index as uint) = Some(txo); }
thinvec
}
};
// Ram it back into the tree
self.tree.insert(&inp.prev_hash.as_uint128(), KEY_LEN, new_node);
}
}
skipped_genesis = true;
}
// Decrement mod the spent txo cache size
self.spent_idx = (self.spent_idx + self.spent_txos.len() as u64 - 1) %
self.spent_txos.len() as u64;
self.last_hash = block.header.prev_blockhash;
return true;
}
/// Get the hash of the last block added to the utxo set
pub fn last_hash(&self) -> Sha256dHash {
self.last_hash
}
/// Get the number of UTXOs in the set
pub fn n_utxos(&self) -> uint {
self.n_utxos as uint
}
/// Get the number of UTXOs in the set
pub fn tree_size(&self) -> uint {
self.tree.node_count()
}
}
#[cfg(test)]
mod tests {
use std::prelude::*;
use std::io::IoResult;
use serialize::hex::FromHex;
use blockdata::constants::genesis_block;
use blockdata::block::Block;
use blockdata::utxoset::UtxoSet;
use network::serialize::Serializable;
#[test]
fn utxoset_serialize_test() {
let mut empty_set = UtxoSet::new(genesis_block(), 100);
let new_block: Block = Serializable::deserialize("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b0201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d026e04ffffffff0100f2052a0100000043410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac00000000010000000321f75f3139a013f50f315b23b0c9a2b6eac31e2bec98e5891c924664889942260000000049483045022100cb2c6b346a978ab8c61b18b5e9397755cbd17d6eb2fe0083ef32e067fa6c785a02206ce44e613f31d9a6b0517e46f3db1576e9812cc98d159bfdaf759a5014081b5c01ffffffff79cda0945903627c3da1f85fc95d0b8ee3e76ae0cfdc9a65d09744b1f8fc85430000000049483045022047957cdd957cfd0becd642f6b84d82f49b6cb4c51a91f49246908af7c3cfdf4a022100e96b46621f1bffcf5ea5982f88cef651e9354f5791602369bf5a82a6cd61a62501fffffffffe09f5fe3ffbf5ee97a54eb5e5069e9da6b4856ee86fc52938c2f979b0f38e82000000004847304402204165be9a4cbab8049e1af9723b96199bfd3e85f44c6b4c0177e3962686b26073022028f638da23fc003760861ad481ead4099312c60030d4cb57820ce4d33812a5ce01ffffffff01009d966b01000000434104ea1feff861b51fe3f5f8a3b12d0f4712db80e919548a80839fc47c6a21e66d957e9c5d8cd108c7a2d2324bad71f9904ac0ae7336507d785b17a2c115e427a32fac00000000".from_hex().unwrap().iter().map(|n| *n)).unwrap();
// Make sure we can't add the block directly, since we are missing the inputs
assert!(!empty_set.update(&new_block));
assert_eq!(empty_set.n_utxos(), 0);
// Add the block manually so that we'll have some UTXOs for the rest of the test
for tx in new_block.txdata.iter() {
empty_set.add_utxos(tx);
}
empty_set.last_hash = new_block.header.hash();
// Check that all the UTXOs were added
assert_eq!(empty_set.n_utxos(), 2);
for tx in new_block.txdata.iter() {
let hash = tx.hash();
for (n, out) in tx.output.iter().enumerate() {
let n = n as u32;
assert_eq!(empty_set.get_utxo(hash, n), Some(&box out.clone()));
}
}
// Check again that we can't add the block, and that this doesn't mess up the
// existing UTXOs
assert!(!empty_set.update(&new_block));
assert_eq!(empty_set.n_utxos(), 2);
for tx in new_block.txdata.iter() {
let hash = tx.hash();
for (n, out) in tx.output.iter().enumerate() {
let n = n as u32;
assert_eq!(empty_set.get_utxo(hash, n), Some(&box out.clone()));
}
}
// Serialize/deserialize the resulting UTXO set
let serial = empty_set.serialize();
assert_eq!(serial, empty_set.serialize_iter().collect());
let deserial: IoResult<UtxoSet> = Serializable::deserialize(serial.iter().map(|n| *n));
assert!(deserial.is_ok());
// Check that all outputs are there
let mut read_set = deserial.unwrap();
for tx in new_block.txdata.iter() {
let hash = tx.hash();
for (n, out) in tx.output.iter().enumerate() {
let n = n as u32;
// Try taking non-existent UTXO
assert_eq!(read_set.take_utxo(hash, 100 + n), None);
// Check take of real UTXO
let ret = read_set.take_utxo(hash, n);
assert_eq!(ret, Some(box out.clone()));
// Try double-take
assert_eq!(read_set.take_utxo(hash, n), None);
}
}
let deserial_again: IoResult<UtxoSet> = Serializable::deserialize(serial.iter().map(|n| *n));
let mut read_again = deserial_again.unwrap();
assert!(read_again.rewind(&new_block));
assert_eq!(read_again.n_utxos(), 0);
for tx in new_block.txdata.iter() {
let hash = tx.hash();
for n in range(0, tx.output.len()) {
let n = n as u32;
let ret = read_again.take_utxo(hash, n);
assert_eq!(ret, None);
}
}
}
}

44
src/internal_macros.rs Normal file
View File

@ -0,0 +1,44 @@
// 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/>.
//
#![macro_escape]
macro_rules! impl_serializable(
($thing:ident, $($field:ident),+) => (
impl Serializable for $thing {
fn serialize(&self) -> Vec<u8> {
let mut ret = vec![];
$( ret.extend(self.$field.serialize().move_iter()); )+
ret
}
fn serialize_iter<'a>(&'a self) -> SerializeIter<'a> {
SerializeIter {
data_iter: None,
sub_iter_iter: box vec![ $( &self.$field as &Serializable, )+ ].move_iter(),
sub_iter: None,
sub_started: false
}
}
fn deserialize<I: Iterator<u8>>(mut iter: I) -> IoResult<$thing> {
use util::misc::prepend_err;
Ok($thing {
$( $field: try!(prepend_err(stringify!($field), Serializable::deserialize(iter.by_ref()))), )+
})
}
}
);
)

65
src/lib.rs Normal file
View File

@ -0,0 +1,65 @@
// 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/>.
//
//! # Rust Bitcoin Library
//!
//! This is a library for which supports the Bitcoin network protocol and associated
//! primitives. It is designed for Rust programs built to work with the Bitcoin
//! network.
//!
//! It is also written entirely in Rust to illustrate the benefits of strong type
//! safety, including ownership and lifetime, for financial and/or cryptographic
//! software.
//!
#![crate_name = "bitcoin"]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
// Experimental features we need
#![feature(globs)]
#![feature(macro_rules)]
#![feature(overloaded_calls)]
#![feature(unsafe_destructor)]
#![comment = "Rust Bitcoin Library"]
#![license = "CC0"]
// Coding conventions
#![deny(non_uppercase_pattern_statics)]
#![deny(uppercase_variables)]
#![deny(non_camel_case_types)]
#![deny(non_snake_case_functions)]
#![deny(unused_mut)]
#![warn(missing_doc)]
extern crate alloc;
extern crate collections;
extern crate core;
extern crate num;
extern crate rand;
extern crate rustrt;
extern crate serialize;
extern crate sync;
extern crate time;
extern crate crypto = "rust-crypto";
mod internal_macros;
pub mod macros;
pub mod network;
pub mod blockdata;
pub mod util;

84
src/macros.rs Normal file
View File

@ -0,0 +1,84 @@
// 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/>.
//
//! # Macros
//!
//! Macros available to users of the Bitcoin library
#![macro_escape]
#[macro_export]
macro_rules! nu_select(
($($name:pat from $rx:expr => $code:expr),+) => ({
nu_select!{ $($name from $rx using recv => $code),+ }
});
($($name:pat from $rx:expr using $meth:ident => $code:expr),+) => ({
use rustrt::local::Local;
use rustrt::task::Task;
use sync::comm::Packet;
let task: Box<Task> = Local::take();
// Is anything already ready to receive? Grab it without waiting.
$(
if (&$rx as &Packet).can_recv() {
let $name = $rx.$meth();
$code
}
)else+
else {
// Start selecting on as many as we need to before getting a bite.
// Keep count of how many, since we need to abort every selection
// that we started.
let mut started_count = 0;
let packets = [ $( &$rx as &Packet, )+ ];
task.deschedule(packets.len(), |task| {
match packets[started_count].start_selection(task) {
Ok(()) => {
started_count += 1;
Ok(())
}
Err(task) => Err(task)
}
});
let mut i = -1;
$(
// Abort every one, but only react to the first
if { i += 1; i < started_count } &&
// If start_selection() failed, abort_selection() will fail too,
// but it still counts as "data available". FIXME: should we swap
// the following two conditions so that packets[started_count - 1].
// abort_selection() is never called?
(packets[i].abort_selection() || i == started_count - 1) {
// Abort the remainder, ignoring their return values
i += 1;
while i < started_count {
packets[i].abort_selection();
i += 1;
}
// React to the first
let $name = $rx.$meth();
$code
}
)else+
else {
println!("i = {} , started_count {}", i, started_count);
fail!("we didn't find the ready receiver, but we should have had one"); }
}
})
)

100
src/network/address.rs Normal file
View File

@ -0,0 +1,100 @@
// 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/>.
//
//! # Bitcoin network addresses
//!
//! This module defines the structures and functions needed to encode
//! network addresses in Bitcoin messages.
//!
use std::fmt;
use std::io::{IoResult, standard_error, InvalidInput};
use network::serialize::Serializable;
/// A message which can be sent on the Bitcoin network
pub struct Address {
/// Services provided by the peer whose address this is
pub services: u64,
/// Network byte-order ipv6 address, or ipv4-mapped ipv6 address
pub address: [u8, ..16],
/// Network port
pub port: u16
}
impl Serializable for Address {
fn serialize(&self) -> Vec<u8> {
let mut rv = vec!();
rv.extend(self.services.serialize().move_iter());
rv.extend(self.address.iter().map(|n| *n));
// Explicitly code the port since it needs to be big-endian
rv.extend([(self.port / 256) as u8, (self.port % 256) as u8].iter().map(|n| *n));
rv
}
fn deserialize<I: Iterator<u8>>(mut iter: I) -> IoResult<Address> {
let ret = Address {
services: try!(Serializable::deserialize(iter.by_ref())),
address: try!(Serializable::deserialize(iter.by_ref())),
// Explicitly code the port since it needs to be big-endian
port: {
let b1 = iter.next();
let b2 = iter.next();
if b1.is_none() || b2.is_none() {
return Err(standard_error(InvalidInput));
}
(b1.unwrap() as u16) * 0x100 + (b2.unwrap() as u16)
}
};
Ok(ret)
}
}
impl fmt::Show for Address {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// TODO: render services and hex-ize address
write!(f, "Address {{services: {}, address: {}, port: {}}}",
self.services, self.address.as_slice(), self.port)
}
}
#[test]
fn serialize_address_test() {
assert!(Address {
services: 1,
address: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x0a, 0, 0, 1],
port: 8333
}.serialize() == Vec::from_slice([1u8, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x0a, 0, 0, 1,
0x20, 0x8d]));
}
#[test]
fn deserialize_address_test() {
let mut addr: IoResult<Address> = Serializable::deserialize([1u8, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x0a, 0, 0, 1,
0x20, 0x8d].iter().map(|n| *n));
assert!(addr.is_ok())
let full = addr.unwrap();
assert!(full.services == 1);
assert!(full.address == [0u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x0a, 0, 0, 1]);
assert!(full.port == 8333);
addr = Serializable::deserialize([1u8, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x0a, 0, 0, 1].iter().map(|n| *n));
assert!(addr.is_err());
}

26
src/network/constants.rs Normal file
View File

@ -0,0 +1,26 @@
// 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/>.
//
//! # Network constants
//!
//! This module provides various constants relating to the Bitcoin network
//! protocol, such as protocol versioning and magic header bytes.
//!
pub static MAGIC_BITCOIN: u32 = 0xD9B4BEF9;
pub static PROTOCOL_VERSION: u32 = 70001;
pub static SERVICES: u64 = 0;
pub static USER_AGENT: &'static str = "bitcoin-rust v0.1";

87
src/network/listener.rs Normal file
View File

@ -0,0 +1,87 @@
// 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/>.
//
//! # Abstract Bitcoin listener
//!
//! This module defines a listener on the Bitcoin network which is able
//! to connect to a peer, send network messages, and receive Bitcoin data.
//!
use std::io::{IoResult, standard_error, ConnectionFailed};
use std::io::timer;
use network::message::{NetworkMessage, Verack};
use network::socket::Socket;
use network::constants;
/// A message which can be sent on the Bitcoin network
pub trait Listener {
/// Return a string encoding of the peer's network address
fn peer<'a>(&'a self) -> &'a str;
/// Return the port we have connected to the peer on
fn port(&self) -> u16;
/// Main listen loop
fn start(&self) -> IoResult<(Receiver<NetworkMessage>, Socket)> {
// Open socket
let mut ret_sock = Socket::new(constants::MAGIC_BITCOIN);
match ret_sock.connect(self.peer(), self.port()) {
Ok(_) => {},
Err(_) => return Err(standard_error(ConnectionFailed))
}
let mut sock = ret_sock.clone();
let (recv_tx, recv_rx) = channel();
// Send version message to peer
let version_message = try!(sock.version_message(0));
try!(sock.send_message(version_message));
// Message loop
spawn(proc() {
let mut handshake_complete = false;
let mut sock = sock;
loop {
// Receive new message
match sock.receive_message() {
Ok(payload) => {
// React to any network messages that affect our state.
match payload {
// Make an exception for verack since there is no response required
Verack => {
// TODO: when the timeout stuff in std::io::net::tcp is sorted out we should
// actually time out if the verack doesn't come in in time
if handshake_complete {
println!("Received second verack (peer is misbehaving)");
} else {
handshake_complete = true;
}
}
_ => {}
};
// We have to pass the message to the main thread for processing,
// unfortunately, because sipa says we have to handle everything
// in order.
recv_tx.send(payload);
}
Err(e) => {
println!("Received error {:} when decoding message. Pausing for 1sec.", e);
timer::sleep(1000);
}
}
}
});
Ok((recv_rx, ret_sock))
}
}

203
src/network/message.rs Normal file
View File

@ -0,0 +1,203 @@
// 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/>.
//
//! # Network message
//!
//! This module defines the `Message` traits which are used
//! for (de)serializing Bitcoin objects for transmission on the network. It
//! also defines (de)serialization routines for many primitives.
//!
use collections::Vec;
use std::io::{IoError, IoResult, InvalidInput, OtherIoError, standard_error};
use blockdata::block;
use network::address::Address;
use network::message_network;
use network::message_blockdata;
use network::serialize::{Serializable, CheckedData};
use util::iter::FixedTakeable;
use util::misc::prepend_err;
/// Serializer for command string
#[deriving(PartialEq, Clone, Show)]
pub struct CommandString(pub String);
impl Serializable for CommandString {
fn serialize(&self) -> Vec<u8> {
let &CommandString(ref inner_str) = self;
let mut rawbytes = [0u8, ..12];
rawbytes.copy_from(inner_str.as_bytes().as_slice());
Vec::from_slice(rawbytes.as_slice())
}
fn deserialize<I: Iterator<u8>>(iter: I) -> IoResult<CommandString> {
let mut fixiter = iter.fixed_take(12);
let rv: String = FromIterator::from_iter(fixiter.by_ref().filter_map(|u| if u > 0 { Some(u as char) } else { None }));
// Once we've read the string, run out the iterator
for _ in fixiter {}
match fixiter.is_err() {
false => Ok(CommandString(rv)),
true => Err(standard_error(InvalidInput))
}
}
}
/// A Network message
pub struct RawNetworkMessage {
/// Magic bytes to identify the network these messages are meant for
pub magic: u32,
/// The actual message data
pub payload: NetworkMessage
}
#[deriving(Show)]
/// A Network message payload. Proper documentation is available on the Bitcoin
/// wiki https://en.bitcoin.it/wiki/Protocol_specification
pub enum NetworkMessage{
/// `version`
Version(message_network::VersionMessage),
/// `verack`
Verack,
/// `addr`
Addr(Vec<(u32, Address)>),
/// `inv`
Inv(Vec<message_blockdata::Inventory>),
/// `getdata`
GetData(Vec<message_blockdata::Inventory>),
/// `notfound`
NotFound(Vec<message_blockdata::Inventory>),
/// `getblocks`
GetBlocks(message_blockdata::GetBlocksMessage),
/// `getheaders`
GetHeaders(message_blockdata::GetHeadersMessage),
// TODO: tx,
/// `block`
Block(block::Block),
/// `headers`
Headers(Vec<block::LoneBlockHeader>),
// TODO: getaddr,
// TODO: mempool,
// TODO: checkorder,
// TODO: submitorder,
// TODO: reply,
/// `ping`
Ping(u64),
/// `pong`
Pong(u64),
// TODO: reject,
// TODO: bloom filtering
// TODO: alert
}
impl RawNetworkMessage {
fn command(&self) -> String {
match self.payload {
Version(_) => "version",
Verack => "verack",
Addr(_) => "addr",
Inv(_) => "inv",
GetData(_) => "getdata",
NotFound(_) => "notfound",
GetBlocks(_) => "getblocks",
GetHeaders(_) => "getheaders",
Block(_) => "block",
Headers(_) => "headers",
Ping(_) => "ping",
Pong(_) => "pong"
}.to_string()
}
}
impl Serializable for RawNetworkMessage {
fn serialize(&self) -> Vec<u8> {
let mut ret = vec![];
ret.extend(self.magic.serialize().move_iter());
ret.extend(CommandString(self.command()).serialize().move_iter());
let payload_data = match self.payload {
Version(ref dat) => dat.serialize(),
Verack => vec![],
Addr(ref dat) => dat.serialize(),
Inv(ref dat) => dat.serialize(),
GetData(ref dat) => dat.serialize(),
NotFound(ref dat) => dat.serialize(),
GetBlocks(ref dat) => dat.serialize(),
GetHeaders(ref dat) => dat.serialize(),
Block(ref dat) => dat.serialize(),
Headers(ref dat) => dat.serialize(),
Ping(ref dat) => dat.serialize(),
Pong(ref dat) => dat.serialize()
};
ret.extend(CheckedData(payload_data).serialize().move_iter());
ret
}
fn deserialize<I: Iterator<u8>>(mut iter: I) -> IoResult<RawNetworkMessage> {
let magic = try!(prepend_err("magic", Serializable::deserialize(iter.by_ref())));
let CommandString(cmd): CommandString = try!(prepend_err("command", Serializable::deserialize(iter.by_ref())));
let CheckedData(raw_payload): CheckedData = try!(prepend_err("payload", Serializable::deserialize(iter.by_ref())));
let payload = match cmd.as_slice() {
"version" => Version(try!(prepend_err("version", Serializable::deserialize(raw_payload.iter().map(|n| *n))))),
"verack" => Verack,
"addr" => Addr(try!(prepend_err("addr", Serializable::deserialize(raw_payload.iter().map(|n| *n))))),
"inv" => Inv(try!(prepend_err("inv", Serializable::deserialize(raw_payload.iter().map(|n| *n))))),
"getdata" => GetData(try!(prepend_err("getdata", Serializable::deserialize(raw_payload.iter().map(|n| *n))))),
"notfound" => NotFound(try!(prepend_err("notfound", Serializable::deserialize(raw_payload.iter().map(|n| *n))))),
"getblocks" => GetBlocks(try!(prepend_err("getblocks", Serializable::deserialize(raw_payload.iter().map(|n| *n))))),
"getheaders" => GetHeaders(try!(prepend_err("getheaders", Serializable::deserialize(raw_payload.iter().map(|n| *n))))),
"block" => Block(try!(prepend_err("block", Serializable::deserialize(raw_payload.iter().map(|n| *n))))),
"headers" => Headers(try!(prepend_err("headers", Serializable::deserialize(raw_payload.iter().map(|n| *n))))),
"ping" => Ping(try!(prepend_err("ping", Serializable::deserialize(raw_payload.iter().map(|n| *n))))),
"pong" => Ping(try!(prepend_err("pong", Serializable::deserialize(raw_payload.iter().map(|n| *n))))),
cmd => {
return Err(IoError {
kind: OtherIoError,
desc: "unknown message type",
detail: Some(format!("`{}` not recognized", cmd))
});
}
};
Ok(RawNetworkMessage {
magic: magic,
payload: payload
})
}
}
#[cfg(test)]
mod test {
use std::io::IoResult;
use network::message::CommandString;
use network::serialize::Serializable;
#[test]
fn serialize_commandstring_test() {
let cs = CommandString(String::from_str("Andrew"));
assert_eq!(cs.serialize(), vec![0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]);
}
#[test]
fn deserialize_commandstring_test() {
let cs: IoResult<CommandString> = Serializable::deserialize([0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0].iter().map(|n| *n));
assert!(cs.is_ok());
assert_eq!(cs.unwrap(), CommandString(String::from_str("Andrew")));
let short_cs: IoResult<CommandString> = Serializable::deserialize([0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0].iter().map(|n| *n));
assert!(short_cs.is_err());
}
// TODO: write tests for full network messages
}

View File

@ -0,0 +1,169 @@
// 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/>.
//
//! # Blockdata network messages
//!
//! This module describes network messages which are used for passing
//! Bitcoin data (blocks and transactions) around.
//!
use std::io::{IoResult, IoError, InvalidInput};
#[cfg(test)]
use serialize::hex::FromHex;
#[cfg(test)]
use util::hash::zero_hash;
use network::constants;
use network::serialize::{Serializable, SerializeIter};
use util::hash::Sha256dHash;
#[deriving(Clone, PartialEq, Show)]
/// The type of an inventory object
pub enum InvType {
/// Error --- these inventories can be ignored
InvError,
/// Transaction
InvTransaction,
/// Block
InvBlock
}
// Some simple messages
/// The `getblocks` message
#[deriving(Show)]
pub struct GetBlocksMessage {
/// The protocol version
pub version: u32,
/// Locator hashes --- ordered newest to oldest. The remote peer will
/// reply with its longest known chain, starting from a locator hash
/// if possible and block 1 otherwise.
pub locator_hashes: Vec<Sha256dHash>,
/// References the block to stop at, or zero to just fetch the maximum 500 blocks
pub stop_hash: Sha256dHash
}
/// The `getheaders` message
#[deriving(Show)]
pub struct GetHeadersMessage {
/// The protocol version
pub version: u32,
/// Locator hashes --- ordered newest to oldest. The remote peer will
/// reply with its longest known chain, starting from a locator hash
/// if possible and block 1 otherwise.
pub locator_hashes: Vec<Sha256dHash>,
/// References the header to stop at, or zero to just fetch the maximum 2000 headers
pub stop_hash: Sha256dHash
}
/// An inventory object --- a reference to a Bitcoin object
#[deriving(Clone, Show)]
pub struct Inventory {
/// The type of object that is referenced
pub inv_type: InvType,
/// The object's hash
pub hash: Sha256dHash
}
impl GetBlocksMessage {
/// Construct a new `getblocks` message
pub fn new(locator_hashes: Vec<Sha256dHash>, stop_hash: Sha256dHash) -> GetBlocksMessage {
GetBlocksMessage {
version: constants::PROTOCOL_VERSION,
locator_hashes: locator_hashes.clone(),
stop_hash: stop_hash
}
}
}
impl_serializable!(GetBlocksMessage, version, locator_hashes, stop_hash)
impl GetHeadersMessage {
/// Construct a new `getheaders` message
pub fn new(locator_hashes: Vec<Sha256dHash>, stop_hash: Sha256dHash) -> GetHeadersMessage {
GetHeadersMessage {
version: constants::PROTOCOL_VERSION,
locator_hashes: locator_hashes,
stop_hash: stop_hash
}
}
}
impl_serializable!(GetHeadersMessage, version, locator_hashes, stop_hash)
impl Serializable for Inventory {
fn serialize(&self) -> Vec<u8> {
let int_type: u32 = match self.inv_type {
InvError => 0,
InvTransaction => 1,
InvBlock => 2
};
let mut rv = vec!();
rv.extend(int_type.serialize().move_iter());
rv.extend(self.hash.serialize().move_iter());
rv
}
fn deserialize<I: Iterator<u8>>(mut iter: I) -> IoResult<Inventory> {
let int_type: u32 = try!(Serializable::deserialize(iter.by_ref()));
Ok(Inventory {
inv_type: match int_type {
0 => InvError,
1 => InvTransaction,
2 => InvBlock,
_ => { return Err(IoError {
kind: InvalidInput,
desc: "bad inventory type field",
detail: None
})}
},
hash: try!(Serializable::deserialize(iter.by_ref()))
})
}
}
#[test]
fn getblocks_message_test() {
let from_sat = "72110100014a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b0000000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap();
let genhash = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".from_hex().unwrap();
let decode: IoResult<GetBlocksMessage> = Serializable::deserialize(from_sat.iter().map(|n| *n));
assert!(decode.is_ok());
let real_decode = decode.unwrap();
assert_eq!(real_decode.version, 70002);
assert_eq!(real_decode.locator_hashes.len(), 1);
assert_eq!(real_decode.locator_hashes[0].as_slice(), genhash.as_slice());
assert_eq!(real_decode.stop_hash.as_slice(), zero_hash().as_slice());
let reserialize = real_decode.serialize();
assert_eq!(reserialize.as_slice(), from_sat.as_slice());
}
#[test]
fn getheaders_message_test() {
let from_sat = "72110100014a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b0000000000000000000000000000000000000000000000000000000000000000".from_hex().unwrap();
let genhash = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".from_hex().unwrap();
let decode: IoResult<GetHeadersMessage> = Serializable::deserialize(from_sat.iter().map(|n| *n));
assert!(decode.is_ok());
let real_decode = decode.unwrap();
assert_eq!(real_decode.version, 70002);
assert_eq!(real_decode.locator_hashes.len(), 1);
assert_eq!(real_decode.locator_hashes[0].as_slice(), genhash.as_slice());
assert_eq!(real_decode.stop_hash.as_slice(), zero_hash().as_slice());
let reserialize = real_decode.serialize();
assert_eq!(reserialize.as_slice(), from_sat.as_slice());
}

View File

@ -0,0 +1,140 @@
// 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/>.
//
//! # Network-related network messages
//!
//! This module defines network messages which describe peers and their
//! capabilities
//!
use std::io::IoResult;
#[cfg(test)]
use serialize::hex::FromHex;
use network::constants;
use network::address::Address;
use network::serialize::Serializable;
use network::socket::Socket;
/// Some simple messages
/// The `version` message
#[deriving(Show)]
pub struct VersionMessage {
/// The P2P network protocol version
pub version: u32,
/// A bitmask describing the services supported by this node
pub services: u64,
/// The time at which the `version` message was sent
pub timestamp: i64,
/// The network address of the peer receiving the message
pub receiver: Address,
/// The network address of the peer sending the message
pub sender: Address,
/// A random nonce used to detect loops in the network
pub nonce: u64,
/// A string describing the peer's software
pub user_agent: String,
/// The height of the maxmimum-work blockchain that the peer is aware of
pub start_height: i32,
/// Whether the receiving peer should relay messages to the sender; used
/// if the sender is bandwidth-limited and would like to support bloom
/// filtering. Defaults to true.
pub relay: bool
}
impl VersionMessage {
// TODO: we have fixed services and relay to 0
/// Constructs a new `version` message
pub fn new(timestamp: i64, mut socket: Socket, nonce: u64, start_height: i32) -> IoResult<VersionMessage> {
let recv_addr = socket.receiver_address();
let send_addr = 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 {
version: constants::PROTOCOL_VERSION,
services: socket.services,
timestamp: timestamp,
receiver: recv_addr.unwrap(),
sender: send_addr.unwrap(),
nonce: nonce,
user_agent: socket.user_agent,
start_height: start_height,
relay: false
})
}
}
impl Serializable for VersionMessage {
fn serialize(&self) -> Vec<u8> {
let mut rv = vec!();
rv.extend(self.version.serialize().move_iter());
rv.extend(self.services.serialize().move_iter());
rv.extend(self.timestamp.serialize().move_iter());
rv.extend(self.receiver.serialize().move_iter());
rv.extend(self.sender.serialize().move_iter());
rv.extend(self.nonce.serialize().move_iter());
rv.extend(self.user_agent.serialize().move_iter());
rv.extend(self.start_height.serialize().move_iter());
if self.version >= 70001 {
rv.extend(self.relay.serialize().move_iter());
}
rv
}
fn deserialize<I: Iterator<u8>>(mut iter: I) -> IoResult<VersionMessage> {
Ok(VersionMessage {
version: try!(Serializable::deserialize(iter.by_ref())),
services: try!(Serializable::deserialize(iter.by_ref())),
timestamp: try!(Serializable::deserialize(iter.by_ref())),
receiver: try!(Serializable::deserialize(iter.by_ref())),
sender: try!(Serializable::deserialize(iter.by_ref())),
nonce: try!(Serializable::deserialize(iter.by_ref())),
user_agent: try!(Serializable::deserialize(iter.by_ref())),
start_height: try!(Serializable::deserialize(iter.by_ref())),
relay: try!(Serializable::deserialize(iter.by_ref()))
})
}
}
#[test]
fn version_message_test() {
// This message is from my satoshi node, morning of May 27 2014
let from_sat = "721101000100000000000000e6e0845300000000010000000000000000000000000000000000ffff0000000000000100000000000000fd87d87eeb4364f22cf54dca59412db7208d47d920cffce83ee8102f5361746f7368693a302e392e39392f2c9f040001".from_hex().unwrap();
let decode: IoResult<VersionMessage> = Serializable::deserialize(from_sat.iter().map(|n| *n));
assert!(decode.is_ok());
let real_decode = decode.unwrap();
assert_eq!(real_decode.version, 70002);
assert_eq!(real_decode.services, 1);
assert_eq!(real_decode.timestamp, 1401217254);
// address decodes should be covered by Address tests
assert_eq!(real_decode.nonce, 16735069437859780935);
assert_eq!(real_decode.user_agent, String::from_str("/Satoshi:0.9.99/"));
assert_eq!(real_decode.start_height, 302892);
assert_eq!(real_decode.relay, true);
let reserialize = real_decode.serialize();
assert_eq!(reserialize.as_slice(), from_sat.as_slice());
}

30
src/network/mod.rs Normal file
View File

@ -0,0 +1,30 @@
// 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/>.
//
//! # Network Support
//!
//! This module defines support for (de)serialization and network transport
//! of Bitcoin data and network messages.
//!
pub mod constants;
pub mod socket;
pub mod serialize;
pub mod address;
pub mod listener;
pub mod message;
pub mod message_blockdata;
pub mod message_network;

722
src/network/serialize.rs Normal file
View File

@ -0,0 +1,722 @@
// 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/>.
//
//! # Network Serialization
//!
//! This module defines the `Serializable` trait which is used for
//! (de)serializing Bitcoin objects for transmission on the network.
//! It also defines (de)serialization routines for many primitives.
//!
use collections::Vec;
use collections::bitv::{Bitv, from_bytes};
use std::io::{IoError, IoResult, InvalidInput, OtherIoError, standard_error};
use std::io::{BufferedReader, BufferedWriter, File, Truncate, Write};
use std::io::fs::rename;
use std::mem::transmute;
use std::u32;
use util::iter::{FixedTake, FixedTakeable, NullIterator};
use util::hash::Sha256dHash;
use util::thinvec::ThinVec;
/// An iterator which returns serialized data one byte at a time
pub struct SerializeIter<'a> {
/// Iterator over actual data
pub data_iter: Option<Box<Iterator<u8>>>,
/// Objects which are serialized through their own `SerializeIter`s
pub sub_iter_iter: Box<Iterator<&'a Serializable>>,
/// Current subiterator
pub sub_iter: Option<Box<SerializeIter<'a>>>,
/// Whether we have started using sub_iter_iter
pub sub_started: bool
}
impl<'a> Iterator<u8> for SerializeIter<'a> {
fn next(&mut self) -> Option<u8> {
let mut ret = None;
// Try to use the data iterator
if self.data_iter.is_some() {
// Unwrap the current data iterator to use it
let mut it = self.data_iter.take_unwrap();
ret = it.next();
// Delete the current data iterator if it's exhausted, by putting
// it back only when it's -not- exhausted
if ret.is_some() { self.data_iter = Some(it); }
}
// Failing that, start using the subobject iterator
if ret.is_none() && !self.sub_started {
// Unwrap the current data iterator to use it
self.sub_started = true;
self.sub_iter = self.sub_iter_iter.next().map(|obj| box obj.serialize_iter());
}
// If it doesn't work, find one that does
while ret.is_none() && self.sub_iter.is_some() {
let mut iter = self.sub_iter.take_unwrap();
ret = iter.next();
self.sub_iter = if ret.is_none() {
self.sub_iter_iter.next().map(|obj| box obj.serialize_iter())
} else {
Some(iter)
}
}
// Eventually we got Some(u8) --- or None and we're exhausted
ret
}
}
/// A string which must be encoded as 12 bytes, used in network message headers
#[deriving(PartialEq, Clone, Show)]
/// Data which must be preceded by a 4-byte checksum
pub struct CheckedData(pub Vec<u8>);
/// An object which can be (de)serialized. If the object can be sent on the
/// Bitcoin network, the serialization must be the standard p2p network
/// serialization.
pub trait Serializable {
/// Turn an object into a bytestring that can be put on the wire
fn serialize(&self) -> Vec<u8>;
/// Serialize an object, returning an iterator rather than complete vector
fn serialize_iter<'a>(&'a self) -> SerializeIter<'a> {
SerializeIter {
data_iter: Some(box self.serialize().move_iter() as Box<Iterator<u8>>),
sub_iter_iter: box NullIterator::<&Serializable>::new(),
sub_iter: None,
sub_started: false
}
}
/// Read an object off the wire
fn deserialize<I: Iterator<u8>>(iter: I) -> IoResult<Self>;
/// Obtain a hash of the object
fn hash(&self) -> Sha256dHash {
Sha256dHash::from_data(self.serialize().as_slice())
}
/// Dump the object to a file
fn serialize_file(&self, p: &Path) -> IoResult<()> {
let tmp_path = p.with_extension("0");
{
let file = File::open_mode(&tmp_path, Truncate, Write);
let mut writer = BufferedWriter::new(file);
for ch in self.serialize_iter() {
try!(writer.write_u8(ch));
}
try!(writer.flush());
}
rename(&tmp_path, p)
}
/// Read the object from a file
fn deserialize_file(p: &Path) -> IoResult<Self> {
let file = try!(File::open(p));
let mut reader = BufferedReader::new(file);
let mut error: IoResult<u8> = Ok(0);
// This is kinda a hacky way to catch file read errors
let ret = Serializable::deserialize(reader.bytes().filter_map(|res| {
if res.is_err() {
error = res;
None
} else {
res.ok()
}
}));
// Return file error if there was one, else parse error
match error {
Ok(_) => ret,
Err(e) => Err(e)
}
}
}
/// A variable-length unsigned integer
#[deriving(PartialEq, Show)]
pub enum VarInt {
/// 8-bit int
VarU8(u8),
/// 16-bit int
VarU16(u16),
/// 32-bit int
VarU32(u32),
/// 64-bit int
VarU64(u64)
}
// Utility functions
/// Convert a Rust uint to a Bitcoin network Varint
pub fn u64_to_varint(n: u64) -> VarInt {
match n {
n if n < 0xFD => VarU8(n as u8),
n if n <= 0xFFFF => VarU16(n as u16),
n if n <= 0xFFFFFFFF => VarU32(n as u32),
n => VarU64(n)
}
}
/// Convert a Bitcoin network Varint to a Rust uint
pub fn varint_to_u64(n: VarInt) -> u64 {
match n {
VarU8(m) => m as u64,
VarU16(m) => m as u64,
VarU32(m) => m as u64,
VarU64(m) => m,
}
}
fn read_uint_le<I: Iterator<u8>>(mut iter: FixedTake<I>) -> Option<u64> {
let (rv, _) = iter.fold((0u64, 1u64), |(old, mult), next| (old + next as u64 * mult, mult * 0x100));
match iter.is_err() {
false => Some(rv),
true => None
}
}
/// Do a double-SHA256 on some data and return the first 4 bytes
fn sha2_checksum(data: &[u8]) -> u32 {
let checksum = Sha256dHash::from_data(data);
read_uint_le(checksum.as_slice().iter().map(|n| *n).fixed_take(4)).unwrap() as u32
}
/// Primitives
impl Serializable for bool {
fn serialize(&self) -> Vec<u8> {
if *self { Vec::from_slice(&[1u8]) } else { Vec::from_slice(&[0u8]) }
}
fn deserialize<I: Iterator<u8>>(mut iter: I) -> IoResult<bool> {
match iter.next() {
Some(u) => Ok(u != 0),
None => Err(standard_error(InvalidInput))
}
}
}
impl Serializable for u8 {
fn serialize(&self) -> Vec<u8> {
Vec::from_slice(&[*self])
}
fn deserialize<I: Iterator<u8>>(mut iter: I) -> IoResult<u8> {
match iter.next() {
Some(u) => Ok(u as u8),
None => Err(standard_error(InvalidInput))
}
}
}
impl Serializable for u16 {
fn serialize(&self) -> Vec<u8> {
unsafe { Vec::from_slice(transmute::<_, [u8, ..2]>(self.to_le())) }
}
fn deserialize<I: Iterator<u8>>(iter: I) -> IoResult<u16> {
match read_uint_le(iter.fixed_take(2)) {
Some(u) => Ok(u as u16),
None => Err(standard_error(InvalidInput))
}
}
}
impl Serializable for u32 {
fn serialize(&self) -> Vec<u8> {
unsafe { Vec::from_slice(transmute::<_, [u8, ..4]>(self.to_le())) }
}
fn deserialize<I: Iterator<u8>>(iter: I) -> IoResult<u32> {
match read_uint_le(iter.fixed_take(4)) {
Some(u) => Ok(u as u32),
None => Err(standard_error(InvalidInput))
}
}
}
impl Serializable for i32 {
fn serialize(&self) -> Vec<u8> {
unsafe { Vec::from_slice(transmute::<_, [u8, ..4]>(self.to_le())) }
}
fn deserialize<I: Iterator<u8>>(iter: I) -> IoResult<i32> {
match read_uint_le(iter.fixed_take(4)) {
Some(u) => Ok(u as i32),
None => Err(standard_error(InvalidInput))
}
}
}
impl Serializable for u64 {
fn serialize(&self) -> Vec<u8> {
unsafe { Vec::from_slice(transmute::<_, [u8, ..8]>(self.to_le())) }
}
fn deserialize<I: Iterator<u8>>(iter: I) -> IoResult<u64> {
match read_uint_le(iter.fixed_take(8)) {
Some(u) => Ok(u as u64),
None => Err(standard_error(InvalidInput))
}
}
}
impl Serializable for i64 {
fn serialize(&self) -> Vec<u8> {
unsafe { Vec::from_slice(transmute::<_, [u8, ..8]>(self.to_le())) }
}
fn deserialize<I: Iterator<u8>>(iter: I) -> IoResult<i64> {
match read_uint_le(iter.fixed_take(8)) {
Some(u) => Ok(u as i64),
None => Err(standard_error(InvalidInput))
}
}
}
impl Serializable for VarInt {
fn serialize(&self) -> Vec<u8> {
match *self {
VarU8(n) => Vec::from_slice(&[n]),
VarU16(n) => { let mut rv = n.serialize(); rv.unshift(0xFD); rv },
VarU32(n) => { let mut rv = n.serialize(); rv.unshift(0xFE); rv },
VarU64(n) => { let mut rv = n.serialize(); rv.unshift(0xFF); rv },
}
}
fn deserialize<I: Iterator<u8>>(mut iter: I) -> IoResult<VarInt> {
match iter.next() {
Some(n) if n < 0xFD => Ok(VarU8(n)),
Some(n) if n == 0xFD => Ok(VarU16(try!(Serializable::deserialize(iter)))),
Some(n) if n == 0xFE => Ok(VarU32(try!(Serializable::deserialize(iter)))),
Some(n) if n == 0xFF => Ok(VarU64(try!(Serializable::deserialize(iter)))),
_ => Err(standard_error(InvalidInput))
}
}
}
macro_rules! serialize_fixvec(
($($size:expr),+) => (
$(
impl Serializable for [u8, ..$size] {
fn serialize(&self) -> Vec<u8> {
Vec::from_slice(self.as_slice())
}
fn deserialize<I: Iterator<u8>>(iter: I) -> IoResult<[u8, ..$size]> {
let mut v = [0u8, ..$size];
let mut fixiter = iter.fixed_take($size);
let mut n = 0;
for ch in fixiter {
v[n] = ch;
n += 1;
}
match fixiter.is_err() {
false => Ok(v),
true => Err(standard_error(InvalidInput))
}
}
}
)+
#[test]
fn test_fixvec() {
$(
let vec = [5u8, ..$size];
let short_vec = [5u8, ..($size - 1)];
assert_eq!(vec.as_slice(), vec.serialize().as_slice());
let decode: IoResult<[u8, ..$size]> = Serializable::deserialize(vec.iter().map(|n| *n));
let short_decode: IoResult<[u8, ..$size]> = Serializable::deserialize(short_vec.iter().map(|n| *n));
assert!(decode.is_ok());
assert!(short_decode.is_err());
assert_eq!(decode.unwrap().as_slice(), vec.as_slice());
)+
}
);
)
// we need to do this in one call so that we can do a test for
// every value; we can't define a new test fn for each invocation
// because there are no gensyms.
serialize_fixvec!(4, 8, 12, 16, 32)
impl Serializable for CheckedData {
fn serialize(&self) -> Vec<u8> {
let &CheckedData(ref data) = self;
let mut ret = (data.len() as u32).serialize();
ret.extend(sha2_checksum(data.as_slice()).serialize().move_iter());
ret.extend(data.iter().map(|n| *n));
ret
}
fn deserialize<I: Iterator<u8>>(mut iter: I) -> IoResult<CheckedData> {
let length: u32 = try!(Serializable::deserialize(iter.by_ref()));
let checksum: u32 = try!(Serializable::deserialize(iter.by_ref()));
let mut fixiter = iter.fixed_take(length as uint);
let v: Vec<u8> = FromIterator::from_iter(fixiter.by_ref());
if fixiter.is_err() {
return Err(IoError {
kind: InvalidInput,
desc: "overrun",
detail: Some(format!("data length given as {:}, but read fewer bytes", length))
});
}
let expected_checksum = sha2_checksum(v.as_slice());
if checksum == expected_checksum {
Ok(CheckedData(v))
} else {
Err(IoError {
kind: OtherIoError,
desc: "bad checksum",
detail: Some(format!("checksum {:4x} did not match expected {:4x}", checksum, expected_checksum)),
})
}
}
}
impl Serializable for String {
fn serialize(&self) -> Vec<u8> {
let mut rv = u64_to_varint(self.len() as u64).serialize();
rv.push_all(self.as_bytes());
rv
}
fn deserialize<I: Iterator<u8>>(mut iter: I) -> IoResult<String> {
let length: VarInt = try!(Serializable::deserialize(iter.by_ref()));
let mut fixiter = iter.fixed_take(varint_to_u64(length) as uint);
let rv: String = FromIterator::from_iter(fixiter.by_ref().map(|u| u as char));
match fixiter.is_err() {
false => Ok(rv),
true => Err(standard_error(InvalidInput))
}
}
}
impl<T: Serializable> Serializable for Vec<T> {
fn serialize(&self) -> Vec<u8> {
let n_elems = u64_to_varint(self.len() as u64);
let mut rv = n_elems.serialize();
for elem in self.iter() {
rv.extend(elem.serialize().move_iter());
}
rv
}
fn deserialize<I: Iterator<u8>>(mut iter: I) -> IoResult<Vec<T>> {
let mut n_elems = varint_to_u64(try!(Serializable::deserialize(iter.by_ref())));
let mut v: Vec<T> = vec![];
while n_elems > 0 {
v.push(try!(Serializable::deserialize(iter.by_ref())));
n_elems -= 1;
}
Ok(v)
}
}
impl<T: Serializable> Serializable for ThinVec<T> {
fn serialize(&self) -> Vec<u8> {
let n_elems = u64_to_varint(self.len() as u64);
let mut rv = n_elems.serialize();
for elem in self.iter() {
rv.extend(elem.serialize().move_iter());
}
rv
}
fn deserialize<I: Iterator<u8>>(mut iter: I) -> IoResult<ThinVec<T>> {
let n_elems = varint_to_u64(try!(Serializable::deserialize(iter.by_ref())));
assert!(n_elems < u32::MAX as u64);
let mut v: ThinVec<T> = ThinVec::with_capacity(n_elems as u32);
for i in range(0, n_elems) {
unsafe {
v.init(i as uint, try!(Serializable::deserialize(iter.by_ref())));
};
}
Ok(v)
}
}
impl<T:Serializable, U:Serializable> Serializable for (T, U) {
fn serialize(&self) -> Vec<u8> {
let &(ref self1, ref self2) = self;
let mut ret = vec![];
ret.extend(self1.serialize().move_iter());
ret.extend(self2.serialize().move_iter());
ret
}
fn deserialize<I: Iterator<u8>>(mut iter: I) -> IoResult<(T, U)> {
Ok((try!(Serializable::deserialize(iter.by_ref())),
try!(Serializable::deserialize(iter.by_ref()))))
}
}
impl<T:Serializable+'static> Serializable for Option<T> {
fn serialize(&self) -> Vec<u8> {
match self {
&Some(ref dat) => {
let mut ret = vec![1];
ret.extend(dat.serialize().move_iter());
ret
},
&None => vec![0]
}
}
fn serialize_iter<'a>(&'a self) -> SerializeIter<'a> {
match self {
&Some(ref dat) => SerializeIter {
data_iter: Some(box Some(1u8).move_iter() as Box<Iterator<u8>>),
sub_iter_iter: box vec![ dat as &Serializable ].move_iter(),
sub_iter: None,
sub_started: false
},
&None => SerializeIter {
data_iter: Some(box Some(0u8).move_iter() as Box<Iterator<u8>>),
sub_iter_iter: box NullIterator::<&Serializable>::new(),
sub_iter: None,
sub_started: false
}
}
}
fn deserialize<I: Iterator<u8>>(mut iter: I) -> IoResult<Option<T>> {
match iter.next() {
Some(0) => Ok(None),
Some(1) => Ok(Some(try!(Serializable::deserialize(iter)))),
_ => Err(standard_error(InvalidInput))
}
}
}
impl <T:Serializable> Serializable for Box<T> {
fn serialize(&self) -> Vec<u8> {
(**self).serialize()
}
fn serialize_iter<'a>(&'a self) -> SerializeIter<'a> {
(**self).serialize_iter()
}
fn deserialize<I: Iterator<u8>>(iter: I) -> IoResult<Box<T>> {
let ret: T = try!(Serializable::deserialize(iter));
Ok(box ret)
}
}
impl Serializable for Bitv {
fn serialize(&self) -> Vec<u8> {
let n_elems = u64_to_varint(self.len() as u64);
let mut rv = n_elems.serialize();
for elem in self.to_bytes().iter() {
rv.extend(elem.serialize().move_iter());
}
rv
}
fn deserialize<I: Iterator<u8>>(mut iter: I) -> IoResult<Bitv> {
let n_elems = varint_to_u64(try!(Serializable::deserialize(iter.by_ref())));
let mut v: Vec<u8> = vec![];
for _ in range(0, (n_elems + 7) / 8) {
v.push(try!(Serializable::deserialize(iter.by_ref())));
}
let mut ret = from_bytes(v.as_slice());
ret.truncate(n_elems as uint); // from_bytes will round up to 8
Ok(ret)
}
}
#[test]
fn serialize_iter_test() {
assert_eq!(true.serialize(), true.serialize_iter().collect());
assert_eq!(1u8.serialize(), 1u8.serialize_iter().collect());
assert_eq!(300u32.serialize(), 300u32.serialize_iter().collect());
assert_eq!(20u64.serialize(), 20u64.serialize_iter().collect());
}
#[test]
fn serialize_int_test() {
// bool
assert_eq!(false.serialize(), Vec::from_slice([0u8]));
assert_eq!(true.serialize(), Vec::from_slice([1u8]));
// u8
assert_eq!(1u8.serialize(), Vec::from_slice([1u8]));
assert_eq!(0u8.serialize(), Vec::from_slice([0u8]));
assert_eq!(255u8.serialize(), Vec::from_slice([255u8]));
// u16
assert_eq!(1u16.serialize(), Vec::from_slice([1u8, 0]));
assert_eq!(256u16.serialize(), Vec::from_slice([0u8, 1]));
assert_eq!(5000u16.serialize(), Vec::from_slice([136u8, 19]));
// u32
assert_eq!(1u32.serialize(), Vec::from_slice([1u8, 0, 0, 0]));
assert_eq!(256u32.serialize(), Vec::from_slice([0u8, 1, 0, 0]));
assert_eq!(5000u32.serialize(), Vec::from_slice([136u8, 19, 0, 0]));
assert_eq!(500000u32.serialize(), Vec::from_slice([32u8, 161, 7, 0]));
assert_eq!(168430090u32.serialize(), Vec::from_slice([10u8, 10, 10, 10]));
// TODO: test negative numbers
assert_eq!(1i32.serialize(), Vec::from_slice([1u8, 0, 0, 0]));
assert_eq!(256i32.serialize(), Vec::from_slice([0u8, 1, 0, 0]));
assert_eq!(5000i32.serialize(), Vec::from_slice([136u8, 19, 0, 0]));
assert_eq!(500000i32.serialize(), Vec::from_slice([32u8, 161, 7, 0]));
assert_eq!(168430090i32.serialize(), Vec::from_slice([10u8, 10, 10, 10]));
// u64
assert_eq!(1u64.serialize(), Vec::from_slice([1u8, 0, 0, 0, 0, 0, 0, 0]));
assert_eq!(256u64.serialize(), Vec::from_slice([0u8, 1, 0, 0, 0, 0, 0, 0]));
assert_eq!(5000u64.serialize(), Vec::from_slice([136u8, 19, 0, 0, 0, 0, 0, 0]));
assert_eq!(500000u64.serialize(), Vec::from_slice([32u8, 161, 7, 0, 0, 0, 0, 0]));
assert_eq!(723401728380766730u64.serialize(), Vec::from_slice([10u8, 10, 10, 10, 10, 10, 10, 10]));
// TODO: test negative numbers
assert_eq!(1i64.serialize(), Vec::from_slice([1u8, 0, 0, 0, 0, 0, 0, 0]));
assert_eq!(256i64.serialize(), Vec::from_slice([0u8, 1, 0, 0, 0, 0, 0, 0]));
assert_eq!(5000i64.serialize(), Vec::from_slice([136u8, 19, 0, 0, 0, 0, 0, 0]));
assert_eq!(500000i64.serialize(), Vec::from_slice([32u8, 161, 7, 0, 0, 0, 0, 0]));
assert_eq!(723401728380766730i64.serialize(), Vec::from_slice([10u8, 10, 10, 10, 10, 10, 10, 10]));
}
#[test]
fn serialize_varint_test() {
assert_eq!(VarU8(10).serialize(), Vec::from_slice([10u8]));
assert_eq!(VarU8(0xFC).serialize(), Vec::from_slice([0xFCu8]));
assert_eq!(VarU16(0xFD).serialize(), Vec::from_slice([0xFDu8, 0xFD, 0]));
assert_eq!(VarU16(0xFFF).serialize(), Vec::from_slice([0xFDu8, 0xFF, 0xF]));
assert_eq!(VarU32(0xF0F0F0F).serialize(), Vec::from_slice([0xFEu8, 0xF, 0xF, 0xF, 0xF]));
assert_eq!(VarU64(0xF0F0F0F0F0E0).serialize(), Vec::from_slice([0xFFu8, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0, 0]));
}
#[test]
fn serialize_vector_test() {
assert_eq!(Vec::from_slice([1u8, 2, 3]).serialize(), Vec::from_slice([3u8, 1, 2, 3]));
// TODO: test vectors of more interesting objects
}
#[test]
fn serialize_strbuf_test() {
assert_eq!(String::from_str("Andrew").serialize(), Vec::from_slice([6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]));
}
#[test]
fn serialize_checkeddata_test() {
let cd = CheckedData(vec![1u8, 2, 3, 4, 5]);
assert_eq!(cd.serialize(), vec![5, 0, 0, 0, 162, 107, 175, 90, 1, 2, 3, 4, 5]);
}
#[test]
fn serialize_box_test() {
assert_eq!((box 1u8).serialize(), vec![1u8]);
assert_eq!((box 1u16).serialize(), vec![1u8, 0]);
assert_eq!((box 1u64).serialize(), vec![1u8, 0, 0, 0, 0, 0, 0, 0]);
}
#[test]
fn serialize_option_test() {
let none: Option<u8> = None;
let none_ser = none.serialize();
let some_ser = Some(0xFFu8).serialize();
assert_eq!(none_ser, vec![0]);
assert_eq!(some_ser, vec![1, 0xFF]);
assert_eq!(none.serialize(), none.serialize_iter().collect());
assert_eq!(Some(true).serialize(), Some(true).serialize_iter().collect());
}
#[test]
fn serialize_bitv_test() {
let bv = Bitv::with_capacity(10, true);
assert_eq!(bv.serialize(), vec![10, 0xFF, 0xC0]);
assert_eq!(bv.serialize(), bv.serialize_iter().collect());
}
#[test]
fn deserialize_int_test() {
// bool
assert_eq!(Serializable::deserialize([58u8, 0].iter().map(|n| *n)), Ok(true));
assert_eq!(Serializable::deserialize([58u8].iter().map(|n| *n)), Ok(true));
assert_eq!(Serializable::deserialize([1u8].iter().map(|n| *n)), Ok(true));
assert_eq!(Serializable::deserialize([0u8].iter().map(|n| *n)), Ok(false));
assert_eq!(Serializable::deserialize([0u8, 1].iter().map(|n| *n)), Ok(false));
// u8
assert_eq!(Serializable::deserialize([58u8].iter().map(|n| *n)), Ok(58u8));
// u16
assert_eq!(Serializable::deserialize([0x01u8, 0x02].iter().map(|n| *n)), Ok(0x0201u16));
assert_eq!(Serializable::deserialize([0xABu8, 0xCD].iter().map(|n| *n)), Ok(0xCDABu16));
assert_eq!(Serializable::deserialize([0xA0u8, 0x0D].iter().map(|n| *n)), Ok(0xDA0u16));
let failure16: IoResult<u16> = Serializable::deserialize([1u8].iter().map(|n| *n));
assert!(failure16.is_err());
// u32
assert_eq!(Serializable::deserialize([0xABu8, 0xCD, 0, 0].iter().map(|n| *n)), Ok(0xCDABu32));
assert_eq!(Serializable::deserialize([0xA0u8, 0x0D, 0xAB, 0xCD].iter().map(|n| *n)), Ok(0xCDAB0DA0u32));
let failure32: IoResult<u32> = Serializable::deserialize([1u8, 2, 3].iter().map(|n| *n));
assert!(failure32.is_err());
// TODO: test negative numbers
assert_eq!(Serializable::deserialize([0xABu8, 0xCD, 0, 0].iter().map(|n| *n)), Ok(0xCDABi32));
assert_eq!(Serializable::deserialize([0xA0u8, 0x0D, 0xAB, 0x2D].iter().map(|n| *n)), Ok(0x2DAB0DA0i32));
let failurei32: IoResult<i32> = Serializable::deserialize([1u8, 2, 3].iter().map(|n| *n));
assert!(failurei32.is_err());
// u64
assert_eq!(Serializable::deserialize([0xABu8, 0xCD, 0, 0, 0, 0, 0, 0].iter().map(|n| *n)), Ok(0xCDABu64));
assert_eq!(Serializable::deserialize([0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99].iter().map(|n| *n)), Ok(0x99000099CDAB0DA0u64));
let failure64: IoResult<u64> = Serializable::deserialize([1u8, 2, 3, 4, 5, 6, 7].iter().map(|n| *n));
assert!(failure64.is_err());
// TODO: test negative numbers
assert_eq!(Serializable::deserialize([0xABu8, 0xCD, 0, 0, 0, 0, 0, 0].iter().map(|n| *n)), Ok(0xCDABi64));
assert_eq!(Serializable::deserialize([0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99].iter().map(|n| *n)), Ok(0x99000099CDAB0DA0i64));
let failurei64: IoResult<i64> = Serializable::deserialize([1u8, 2, 3, 4, 5, 6, 7].iter().map(|n| *n));
assert!(failurei64.is_err());
}
#[test]
fn deserialize_vec_test() {
assert_eq!(Serializable::deserialize([3u8, 2, 3, 4].iter().map(|n| *n)), Ok(vec![2u8, 3, 4]));
assert_eq!(Serializable::deserialize([4u8, 2, 3, 4, 5, 6].iter().map(|n| *n)), Ok(vec![2u8, 3, 4, 5]));
}
#[test]
fn deserialize_strbuf_test() {
assert_eq!(Serializable::deserialize([6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77].iter().map(|n| *n)), Ok(String::from_str("Andrew")));
}
#[test]
fn deserialize_checkeddata_test() {
let cd: IoResult<CheckedData> = Serializable::deserialize([5u8, 0, 0, 0, 162, 107, 175, 90, 1, 2, 3, 4, 5].iter().map(|n| *n));
assert!(cd.is_ok());
assert_eq!(cd.unwrap(), CheckedData(Vec::from_slice([1u8, 2, 3, 4, 5])));
}
#[test]
fn deserialize_option_test() {
let none: IoResult<Option<u8>> = Serializable::deserialize([0u8].iter().map(|n| *n));
let good: IoResult<Option<u8>> = Serializable::deserialize([1u8, 0xFF].iter().map(|n| *n));
let bad: IoResult<Option<u8>> = Serializable::deserialize([2u8].iter().map(|n| *n));
assert!(bad.is_err());
assert_eq!(none, Ok(None));
assert_eq!(good, Ok(Some(0xFF)));
}
#[test]
fn deserialize_box_test() {
let zero: IoResult<Box<u8>> = Serializable::deserialize([0u8].iter().map(|n| *n));
let one: IoResult<Box<u8>> = Serializable::deserialize([1u8].iter().map(|n| *n));
assert_eq!(zero, Ok(box 0));
assert_eq!(one, Ok(box 1));
}
#[test]
fn deserialize_bitv_test() {
let bv: IoResult<Bitv> = Serializable::deserialize([10u8, 0xFF, 0xC0].iter().map(|n| *n));
assert!(bv.is_ok());
assert_eq!(bv.unwrap(), Bitv::with_capacity(10, true));
}

211
src/network/socket.rs Normal file
View File

@ -0,0 +1,211 @@
// 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/>.
//
//! # Sockets
//!
//! This module provides support for low-level network communication.
//!
use time::now;
use std::rand::task_rng;
use rand::Rng;
use std::io::{IoError, IoResult, NotConnected, OtherIoError, standard_error};
use std::io::net::{ip, tcp};
use network::constants;
use network::address::Address;
use network::message::{RawNetworkMessage, NetworkMessage, Version};
use network::serialize::Serializable;
use network::message_network::VersionMessage;
/// Format an IP address in the 16-byte bitcoin protocol serialization
fn ipaddr_to_bitcoin_addr(ipaddr: &ip::IpAddr) -> [u8, ..16] {
match *ipaddr {
ip::Ipv4Addr(a, b, c, d) =>
[0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0xff, 0xff, a, b, c, d],
ip::Ipv6Addr(a, b, c, d, e, f, g, h) =>
[(a / 0x100) as u8, (a % 0x100) as u8, (b / 0x100) as u8, (b % 0x100) as u8,
(c / 0x100) as u8, (c % 0x100) as u8, (d / 0x100) as u8, (d % 0x100) as u8,
(e / 0x100) as u8, (e % 0x100) as u8, (f / 0x100) as u8, (f % 0x100) as u8,
(g / 0x100) as u8, (g % 0x100) as u8, (h / 0x100) as u8, (h % 0x100) as u8 ]
}
}
/// A network socket along with information about the peer
#[deriving(Clone)]
pub struct Socket {
/// The underlying network data stream
stream: Option<tcp::TcpStream>,
/// Services supported by us
pub services: u64,
/// Our user agent
pub user_agent: String,
/// Nonce to identify our `version` messages
pub version_nonce: u64,
/// Network magic
pub magic: u32
}
impl Socket {
// TODO: we fix services to 0
/// Construct a new socket
pub fn new(magic: u32) -> Socket {
let mut rng = task_rng();
Socket {
stream: None,
services: 0,
version_nonce: rng.gen(),
user_agent: String::from_str(constants::USER_AGENT),
magic: magic
}
}
/// Connect to the peer
pub fn connect(&mut self, host: &str, port: u16) -> IoResult<()> {
match tcp::TcpStream::connect(host, port) {
Ok(s) => {
self.stream = Some(s);
Ok(())
}
Err(e) => Err(e)
}
}
/// Peer address
pub fn receiver_address(&mut self) -> IoResult<Address> {
match self.stream {
Some(ref mut s) => match s.peer_name() {
Ok(addr) => {
Ok(Address {
services: self.services,
address: ipaddr_to_bitcoin_addr(&addr.ip),
port: addr.port
})
}
Err(e) => Err(e)
},
None => Err(standard_error(NotConnected))
}
}
/// Our own address
pub fn sender_address(&mut self) -> IoResult<Address> {
match self.stream {
Some(ref mut s) => match s.socket_name() {
Ok(addr) => {
Ok(Address {
services: self.services,
address: ipaddr_to_bitcoin_addr(&addr.ip),
port: addr.port
})
}
Err(e) => Err(e)
},
None => Err(standard_error(NotConnected))
}
}
/// Produce a version message appropriate for this socket
pub fn version_message(&mut self, start_height: i32) -> IoResult<NetworkMessage> {
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 {
version: constants::PROTOCOL_VERSION,
services: constants::SERVICES,
timestamp: timestamp,
receiver: recv_addr.unwrap(),
sender: send_addr.unwrap(),
nonce: self.version_nonce,
user_agent: self.user_agent.clone(),
start_height: start_height,
relay: false
}))
}
/// Send a general message across the line
pub fn send_message(&mut self, payload: NetworkMessage) -> IoResult<()> {
if self.stream.is_none() {
Err(standard_error(NotConnected))
}
else {
let stream = self.stream.get_mut_ref();
let message = RawNetworkMessage { magic: self.magic, payload: payload };
match stream.write(message.serialize().as_slice()) {
Ok(_) => Ok(()),
Err(e) => Err(e)
}
}
}
/// Receive the next message from the peer, decoding the network header
/// and verifying its correctness. Returns the undecoded payload.
pub fn receive_message(&mut self) -> IoResult<NetworkMessage> {
match self.stream {
None => Err(standard_error(NotConnected)),
Some(ref mut s) => {
let mut read_err = None;
// 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.
let ret: IoResult<RawNetworkMessage> = {
// Set up iterator so we will catch network errors properly
let iter = s.bytes().filter_map(|res|
match res {
Ok(ch) => Some(ch),
Err(e) => { read_err = Some(e); None }
});
// Receive message
Serializable::deserialize(iter)
};
// Return
match read_err {
// Network errors get priority since they are probably more meaningful
Some(e) => Err(e),
_ => {
match ret {
// Next come parse errors
Err(e) => Err(e),
Ok(ret) => {
// Finally magic (this should come before parse error, but we can't
// get to it if the deserialization failed). TODO restructure this
if ret.magic != self.magic {
Err(IoError {
kind: OtherIoError,
desc: "bad magic",
detail: Some(format!("got magic {:x}, expected {:x}", ret.magic, self.magic)),
})
} else {
Ok(ret.payload)
}
}
}
}
}
}
}
}
}

204
src/util/hash.rs Normal file
View File

@ -0,0 +1,204 @@
// 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/>.
//
//! # Hash functions
//!
//! Utility functions related to hashing data, including merkleization
use collections::bitv::{Bitv, from_bytes};
use core::char::from_digit;
use core::cmp::min;
use std::fmt;
use std::io::{IoResult, IoError, InvalidInput};
use std::mem::transmute;
use crypto::digest::Digest;
use crypto::sha2;
use network::serialize::Serializable;
use util::iter::FixedTakeable;
use util::uint::Uint128;
use util::uint::Uint256;
/// A Bitcoin hash, 32-bytes, computed from x as SHA256(SHA256(x))
pub struct Sha256dHash([u8, ..32]);
/// Returns the all-zeroes "hash"
pub fn zero_hash() -> Sha256dHash { Sha256dHash([0u8, ..32]) }
impl Sha256dHash {
/// Create a hash by hashing some data
pub fn from_data(data: &[u8]) -> Sha256dHash {
let Sha256dHash(mut ret) = zero_hash();
let mut sha2 = sha2::Sha256::new();
sha2.input(data);
sha2.result(ret.as_mut_slice());
sha2.reset();
sha2.input(ret.as_slice());
sha2.result(ret.as_mut_slice());
Sha256dHash(ret)
}
/// Returns a slice containing the bytes of the has
pub fn as_slice<'a>(&'a self) -> &'a [u8] {
let &Sha256dHash(ref data) = self;
data.as_slice()
}
/// Converts a hash to a bit vector
pub fn as_bitv(&self) -> Bitv {
from_bytes(self.as_slice())
}
/// Converts a hash to a Uint256, interpreting it as a little endian encoding.
pub fn as_uint256(&self) -> Uint256 {
let &Sha256dHash(data) = self;
unsafe { Uint256(transmute(data)) }
}
/// Converts a hash to a Uint128, interpreting it as a little endian encoding.
pub fn as_uint128(&self) -> Uint128 {
let &Sha256dHash(data) = self;
unsafe { Uint128(transmute([data[16], data[17], data[18], data[19], data[20],
data[21], data[22], data[23], data[24], data[25],
data[26], data[27], data[28], data[29], data[30],
data[31]])) }
}
/// Human-readable hex output
pub fn le_hex_string(&self) -> String {
let &Sha256dHash(data) = self;
let mut ret = String::with_capacity(64);
for i in range(0u, 32).rev() {
ret.push_char(from_digit((data[i] / 0x10) as uint, 16).unwrap());
ret.push_char(from_digit((data[i] & 0x0f) as uint, 16).unwrap());
}
ret
}
}
impl Clone for Sha256dHash {
fn clone(&self) -> Sha256dHash {
*self
}
}
impl PartialEq for Sha256dHash {
fn eq(&self, other: &Sha256dHash) -> bool {
let &Sha256dHash(ref mydata) = self;
let &Sha256dHash(ref yourdata) = other;
for i in range(0u, 32) {
if mydata[i] != yourdata[i] {
return false;
}
}
return true;
}
}
impl Serializable for Sha256dHash {
fn serialize(&self) -> Vec<u8> {
let &Sha256dHash(ref data) = self;
data.iter().map(|n| *n).collect()
}
fn deserialize<I: Iterator<u8>>(iter: I) -> IoResult<Sha256dHash> {
let Sha256dHash(mut ret) = zero_hash();
let mut fixediter = iter.enumerate().fixed_take(32);
for (n, data) in fixediter {
ret[n] = data;
}
match fixediter.is_err() {
false => Ok(Sha256dHash(ret)),
true => Err(IoError {
kind: InvalidInput,
desc: "unexpected end of input",
detail: Some(format!("Need 32 bytes, was {:} short.", fixediter.remaining()))
})
}
}
}
impl fmt::LowerHex for Sha256dHash {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let &Sha256dHash(ref data) = self;
let mut rv = [0, ..64];
let mut hex = data.iter().rev().map(|n| *n).enumerate();
for (i, ch) in hex {
rv[2*i] = from_digit(ch as uint / 16, 16).unwrap() as u8;
rv[2*i + 1] = from_digit(ch as uint % 16, 16).unwrap() as u8;
}
f.write(rv.as_slice())
}
}
impl fmt::Show for Sha256dHash {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:x}", *self)
}
}
//TODO: this should be an impl and the function have first parameter self.
//See https://github.com/rust-lang/rust/issues/15060 for why this isn't so.
//impl<T: Serializable> Vec<T> {
/// Construct a merkle tree from a vector, with elements ordered as
/// they were in the original vector, and return the merkle root.
pub fn merkle_root<T: Serializable>(data: &[T]) -> Sha256dHash {
fn merkle_root(data: Vec<Sha256dHash>) -> Sha256dHash {
// Base case
if data.len() < 1 {
return zero_hash();
}
if data.len() < 2 {
return data[0];
}
// Recursion
let mut next = vec![];
for idx in range(0, (data.len() + 1) / 2) {
let idx1 = 2 * idx;
let idx2 = min(idx1 + 1, data.len() - 1);
let to_hash = data[idx1].hash().serialize().append(data[idx2].hash().serialize().as_slice());
next.push(to_hash.hash());
}
merkle_root(next)
}
merkle_root(data.iter().map(|obj| obj.hash()).collect())
}
//}
#[cfg(test)]
mod tests {
use std::prelude::*;
use collections::bitv::from_bytes;
use util::hash::Sha256dHash;
use util::misc::hex_bytes;
#[test]
fn test_sha256d() {
assert_eq!(Sha256dHash::from_data(&[]).as_slice(),
hex_bytes("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456").unwrap().as_slice());
assert_eq!(Sha256dHash::from_data(&[]).le_hex_string(),
"56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d".to_string());
assert_eq!(Sha256dHash::from_data(b"TEST").as_slice(),
hex_bytes("d7bd34bfe44a18d2aa755a344fe3e6b06ed0473772e6dfce16ac71ba0b0a241c").unwrap().as_slice());
}
#[test]
fn test_hash_to_bitvset() {
assert_eq!(Sha256dHash::from_data(&[]).as_bitv(),
from_bytes(hex_bytes("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456").unwrap().as_slice()));
}
}

147
src/util/iter.rs Normal file
View File

@ -0,0 +1,147 @@
// 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/>.
//
//! # Iterator adaptors
//!
//! Iterator adaptors needed by Bitcoin but not provided by the Rust
//! standard library.
/// An iterator that just returns None
pub struct NullIterator<T>;
impl<T> Iterator<T> for NullIterator<T> {
#[inline]
fn next(&mut self) -> Option<T> { None }
#[inline]
fn size_hint(&self) -> (uint, Option<uint>) { (0, Some(0)) }
}
impl<T> NullIterator<T> {
/// Creates a new NullIterator
pub fn new() -> NullIterator<T> { NullIterator }
}
/// An Iterator which will give n elements of the contained iterator
/// before returning None. If the contained iterator returns None too
/// early,
pub struct FixedTake<I> {
iter: I,
n_elems: uint,
is_err: bool
}
impl<T, I: Iterator<T>> Iterator<T> for FixedTake<I> {
fn next(&mut self) -> Option<T> {
if self.n_elems == 0 {
None
} else {
self.n_elems -= 1;
match self.iter.next() {
Some(e) => Some(e),
None => {
self.is_err = true;
None
}
}
}
}
}
impl<I> FixedTake<I> {
/// Constructs a FixedTake iterator from an underlying iterator
pub fn new(iter: I, n_elems: uint) -> FixedTake<I> {
FixedTake { iter: iter, n_elems: n_elems, is_err: false }
}
/// Indicates whether the underlying iterator has ended early
pub fn is_err(&self) -> bool {
self.is_err
}
/// Number of remaining elements
pub fn remaining(&self) -> uint {
self.n_elems
}
}
/// An iterator that returns at most `n_elems` elements, entering an error
/// state if the underlying iterator yields fewer than `n_elems` elements.
pub trait FixedTakeable<I> {
/// Returns an iterator similar to Take but which detects if the original
/// iterator runs out early
fn fixed_take(self, n_elems: uint) -> FixedTake<I>;
}
impl<T, I: Iterator<T>> FixedTakeable<I> for I {
fn fixed_take(self, n_elems: uint) -> FixedTake<I> {
FixedTake::new(self, n_elems)
}
}
/// An iterator that returns pairs of elements
pub struct Pair<A, I> {
iter: I,
last_elem: Option<A>
}
impl<A, I: Iterator<A>> Iterator<(A, A)> for Pair<A, I> {
#[inline]
fn next(&mut self) -> Option<(A, A)> {
let elem1 = self.iter.next();
if elem1.is_none() {
None
} else {
let elem2 = self.iter.next();
if elem2.is_none() {
self.last_elem = elem1;
None
} else {
Some((elem1.unwrap(), elem2.unwrap()))
}
}
}
#[inline]
fn size_hint(&self) -> (uint, Option<uint>) {
match self.iter.size_hint() {
(n, None) => (n/2, None),
(n, Some(m)) => (n/2, Some(m/2))
}
}
}
impl<A, I: Iterator<A>> Pair<A, I> {
/// Returns the last element of the iterator if there were an odd
/// number of elements remaining before it was Pair-ified.
#[inline]
pub fn remainder(self) -> Option<A> {
self.last_elem
}
}
/// Returns an iterator that returns elements of the original iterator 2 at a time
pub trait Pairable<A> {
/// Returns an iterator that returns elements of the original iterator 2 at a time
fn pair(self) -> Pair<A, Self>;
}
impl<A, I: Iterator<A>> Pairable<A> for I {
/// Creates an iterator that yields pairs ef elements from the underlying
/// iterator, yielding `None` when there are fewer than two elements to
/// return.
#[inline]
fn pair(self) -> Pair<A, I> {
Pair{iter: self, last_elem: None}
}
}

90
src/util/misc.rs Normal file
View File

@ -0,0 +1,90 @@
// 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/>.
//
//! # Miscellaneous functions
//!
//! Various utility functions
use std::io::{IoError, IoResult, InvalidInput};
use util::iter::Pairable;
/// Convert a hexadecimal-encoded string to its corresponding bytes
pub fn hex_bytes(s: &str) -> IoResult<Vec<u8>> {
let mut v = vec![];
let mut iter = s.chars().pair();
// Do the parsing
try!(iter.fold(Ok(()), |e, (f, s)|
if e.is_err() { return e; }
else {
match (f.to_digit(16), s.to_digit(16)) {
(None, _) => return Err(IoError {
kind: InvalidInput,
desc: "invalid hex character",
detail: Some(format!("expected hex, got {:}", f))
}),
(_, None) => return Err(IoError {
kind: InvalidInput,
desc: "invalid hex character",
detail: Some(format!("expected hex, got {:}", s))
}),
(Some(f), Some(s)) => { v.push((f * 0x10 + s) as u8); Ok(()) }
}
}
));
// Check that there was no remainder
match iter.remainder() {
Some(_) => Err(IoError {
kind: InvalidInput,
desc: "hexstring of odd length",
detail: None
}),
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: IoResult<T>) -> IoResult<T> {
res.map_err(|err| {
IoError {
kind: err.kind,
desc: err.desc,
detail: Some(format!("{:s}: {:}", s, match err.detail { Some(s) => s, None => String::new() }))
}
})
}
/// Dump an error message to the screen
pub fn consume_err<T>(s: &str, res: IoResult<T>) {
match res {
Ok(_) => {},
Err(e) => { println!("{:s}: {:}", s, e); }
};
}
#[cfg(test)]
mod tests {
use std::prelude::*;
use util::misc::hex_bytes;
#[test]
fn test_hex_bytes() {
assert_eq!(hex_bytes("abcd").unwrap().as_slice(), [171u8, 205].as_slice());
assert!(hex_bytes("abcde").is_err());
assert!(hex_bytes("aBcDeF").is_ok());
assert!(hex_bytes("aBcD4eFL").is_err());
}
}

41
src/util/mod.rs Normal file
View File

@ -0,0 +1,41 @@
// 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/>.
//
//! # Utility functions
//!
//! Functions needed by all parts of the Bitcoin library
pub mod hash;
pub mod iter;
pub mod misc;
pub mod patricia_tree;
pub mod thinvec;
pub mod uint;
/// A trait which allows numbers to act as fixed-size bit arrays
pub trait BitArray {
/// Is bit set?
fn bit(&self, idx: uint) -> bool;
/// Returns an array which is just the bits from start to end
fn bit_slice(&self, start: uint, end: uint) -> Self;
/// Bitwise and with `n` ones
fn mask(&self, n: uint) -> Self;
/// Trailing zeros
fn trailing_zeros(&self) -> uint;
}

546
src/util/patricia_tree.rs Normal file
View File

@ -0,0 +1,546 @@
// 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/>.
//
//! # Patricia/Radix Trie
//!
//! A Patricia trie is a trie in which nodes with only one child are
//! merged with the child, giving huge space savings for sparse tries.
//! A radix tree is more general, working with keys that are arbitrary
//! strings; a Patricia tree uses bitstrings.
//!
use core::fmt::Show;
use core::iter::ByRef;
use core::cmp;
use std::num::{Zero, One};
use std::io::{IoResult, InvalidInput, standard_error};
use network::serialize::{Serializable, SerializeIter};
use util::BitArray;
use util::misc::prepend_err;
/// Patricia troo
pub struct PatriciaTree<T, K> {
data: Option<T>,
child_l: Option<Box<PatriciaTree<T, K>>>,
child_r: Option<Box<PatriciaTree<T, K>>>,
skip_prefix: K,
skip_len: u8
}
impl<T, K:BitArray+Eq+Zero+One+BitXor<K,K>+Shl<uint,K>+Shr<uint,K>> PatriciaTree<T, K> {
/// Constructs a new Patricia tree
pub fn new() -> PatriciaTree<T, K> {
PatriciaTree {
data: None,
child_l: None,
child_r: None,
skip_prefix: Zero::zero(),
skip_len: 0
}
}
/// Lookup a value by exactly matching `key` and return a referenc
pub fn lookup_mut<'a>(&'a mut self, key: &K, key_len: uint) -> Option<&'a mut T> {
// Caution: `lookup_mut` never modifies its self parameter (in fact its
// internal recursion uses a non-mutable self, so we are OK to just
// transmute our self pointer into a mutable self before passing it in.
use std::mem::transmute;
unsafe { transmute(self.lookup(key, key_len)) }
}
/// Lookup a value by exactly matching `key` and return a mutable reference
pub fn lookup<'a>(&'a self, key: &K, key_len: uint) -> Option<&'a T> {
let mut node = self;
let mut key_idx = 0;
loop {
// If the search key is shorter than the node prefix, there is no
// way we can match, so fail.
if key_len - key_idx < node.skip_len as uint {
return None;
}
// Key fails to match prefix --- no match
if node.skip_prefix != key.bit_slice(key_idx, key_idx + node.skip_len as uint) {
return None;
}
// Key matches prefix: if they are an exact match, return the data
if node.skip_len as uint == key_len - key_idx {
return node.data.as_ref();
} else {
// Key matches prefix: search key longer than node key, recurse
key_idx += 1 + node.skip_len as uint;
let subtree = if key.bit(key_idx - 1) { &node.child_r } else { &node.child_l };
match subtree {
&Some(ref bx) => {
node = &**bx; // bx is a &Box<U> here, so &**bx gets &U
}
&None => { return None; }
}
}
} // end loop
}
/// Inserts a value with key `key`, returning true on success. If a value is already
/// stored against `key`, do nothing and return false.
#[inline]
pub fn insert(&mut self, key: &K, key_len: uint, value: T) -> bool {
self.real_insert(key, key_len, value, false)
}
/// Inserts a value with key `key`, returning true on success. If a value is already
/// stored against `key`, overwrite it and return false.
#[inline]
pub fn insert_or_update(&mut self, key: &K, key_len: uint, value: T) -> bool {
self.real_insert(key, key_len, value, true)
}
fn real_insert(&mut self, key: &K, key_len: uint, value: T, overwrite: bool) -> bool {
let mut node = self;
let mut idx = 0;
loop {
// Mask in case search key is shorter than node key
let slice_len = cmp::min(node.skip_len as uint, key_len - idx);
let masked_prefix = node.skip_prefix.mask(slice_len);
let key_slice = key.bit_slice(idx, idx + slice_len);
// Prefixes do not match: split key
if masked_prefix != key_slice {
let diff = (masked_prefix ^ key_slice).trailing_zeros();
// Remove the old node's children
let child_l = node.child_l.take();
let child_r = node.child_r.take();
let value_neighbor = node.data.take();
let tmp = node; // borrowck hack
let (insert, neighbor) = if key_slice.bit(diff)
{ (&mut tmp.child_r, &mut tmp.child_l) }
else { (&mut tmp.child_l, &mut tmp.child_r) };
*insert = Some(box PatriciaTree {
data: None,
child_l: None,
child_r: None,
skip_prefix: key.bit_slice(idx + diff + 1, key_len),
skip_len: (key_len - idx - diff - 1) as u8
});
*neighbor = Some(box PatriciaTree {
data: value_neighbor,
child_l: child_l,
child_r: child_r,
skip_prefix: tmp.skip_prefix >> (diff + 1),
skip_len: tmp.skip_len - diff as u8 - 1
});
// Chop the prefix down
tmp.skip_len = diff as u8;
tmp.skip_prefix = tmp.skip_prefix.mask(diff);
// Recurse
idx += 1 + diff;
node = &mut **insert.get_mut_ref();
}
// Prefixes match
else {
let slice_len = key_len - idx;
// Search key is shorter than skip prefix: truncate the prefix and attach
// the old data as a child
if node.skip_len as uint > slice_len {
// Remove the old node's children
let child_l = node.child_l.take();
let child_r = node.child_r.take();
let value_neighbor = node.data.take();
// Put the old data in a new child, with the remainder of the prefix
let new_child = if node.skip_prefix.bit(slice_len)
{ &mut node.child_r } else { &mut node.child_l };
*new_child = Some(box PatriciaTree {
data: value_neighbor,
child_l: child_l,
child_r: child_r,
skip_prefix: node.skip_prefix >> (slice_len + 1),
skip_len: node.skip_len - slice_len as u8 - 1
});
// Chop the prefix down and put the new data in place
node.skip_len = slice_len as u8;
node.skip_prefix = key_slice;
node.data = Some(value);
return true;
}
// If we have an exact match, great, insert it
else if node.skip_len as uint == slice_len {
if node.data.is_none() {
node.data = Some(value);
return true;
}
if overwrite {
node.data = Some(value);
}
return false;
}
// Search key longer than node key, recurse
else {
let tmp = node; // hack to appease borrowck
idx += tmp.skip_len as uint + 1;
let subtree = if key.bit(idx - 1)
{ &mut tmp.child_r } else { &mut tmp.child_l };
// Recurse, adding a new node if necessary
if subtree.is_none() {
*subtree = Some(box PatriciaTree {
data: None,
child_l: None,
child_r: None,
skip_prefix: key.bit_slice(idx, key_len),
skip_len: key_len as u8 - idx as u8
});
}
// subtree.get_mut_ref is a &mut Box<U> here, so &mut ** gets a &mut U
node = &mut **subtree.get_mut_ref();
} // end search_len vs prefix len
} // end if prefixes match
} // end loop
}
/// Deletes a value with key `key`, returning it on success. If no value with
/// the given key is found, return None
pub fn delete(&mut self, key: &K, key_len: uint) -> Option<T> {
/// 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)
fn recurse<T, K:BitArray+Eq+Zero+One+Add<K,K>+Shr<uint,K>+Shl<uint,K>>(tree: &mut PatriciaTree<T, K>, key: &K, key_len: uint) -> (bool, Option<T>) {
// If the search key is shorter than the node prefix, there is no
// way we can match, so fail.
if key_len < tree.skip_len as uint {
return (false, None);
}
// Key fails to match prefix --- no match
if tree.skip_prefix != key.mask(tree.skip_len as uint) {
return (false, None);
}
// If we are here, the key matches the prefix
if tree.skip_len as uint == key_len {
// Exact match -- delete and return
let ret = tree.data.take();
let bit = tree.child_r.is_some();
// First try to consolidate if there is only one child
if tree.child_l.is_some() && tree.child_r.is_some() {
// Two children means we cannot consolidate or delete
return (false, ret);
}
match (tree.child_l.take(), tree.child_r.take()) {
(Some(_), Some(_)) => unreachable!(),
(Some(consolidate), None) | (None, Some(consolidate)) => {
tree.data = consolidate.data;
tree.child_l = consolidate.child_l;
tree.child_r = consolidate.child_r;
let new_bit = if bit { let ret: K = One::one();
ret << (tree.skip_len as uint) }
else { Zero::zero() };
tree.skip_prefix = tree.skip_prefix +
new_bit +
(consolidate.skip_prefix << (1 + tree.skip_len as uint));
tree.skip_len += 1 + consolidate.skip_len;
return (false, ret);
}
// No children means this node is deletable
(None, None) => { return (true, ret); }
}
}
// Otherwise, the key is longer than the prefix and we need to recurse
let next_bit = key.bit(tree.skip_len as uint);
// Recursively get the return value. This awkward scope is required
// to shorten the time we mutably borrow the node's children -- we
// might want to borrow the sibling later, so the borrow needs to end.
let ret = {
let target = if next_bit { &mut tree.child_r } else { &mut tree.child_l };
// If we can't recurse, fail
if target.is_none() {
return (false, None);
}
// Otherwise, do it
let (delete_child, ret) = recurse(&mut **target.get_mut_ref(),
&key.shr(&(tree.skip_len as uint + 1)),
key_len - tree.skip_len as uint - 1);
if delete_child {
target.take();
}
ret
};
// The above block may have deleted the target. If we now have only one
// child, merge it into the parent. (If we have no children, mark this
// node for deletion.)
if tree.data.is_some() {
// First though, if this is a data node, we can neither delete nor
// consolidate it.
return (false, ret);
}
match (tree.child_r.is_some(), tree.child_l.take(), tree.child_r.take()) {
// Two children? Can't do anything, just sheepishly put them back
(_, Some(child_l), Some(child_r)) => {
tree.child_l = Some(child_l);
tree.child_r = Some(child_r);
return (false, ret);
}
// One child? Consolidate
(bit, Some(consolidate), None) | (bit, None, Some(consolidate)) => {
tree.data = consolidate.data;
tree.child_l = consolidate.child_l;
tree.child_r = consolidate.child_r;
let new_bit = if bit { let ret: K = One::one();
ret << (tree.skip_len as uint) }
else { Zero::zero() };
tree.skip_prefix = tree.skip_prefix +
new_bit +
(consolidate.skip_prefix << (1 + tree.skip_len as uint));
tree.skip_len += 1 + consolidate.skip_len;
return (false, ret);
}
// No children? Delete
(_, None, None) => {
return (true, ret);
}
}
}
let (_, ret) = recurse(self, key, key_len);
ret
}
/// Count all the nodes
pub fn node_count(&self) -> uint {
fn recurse<T, K>(node: &Option<Box<PatriciaTree<T, K>>>) -> uint {
match node {
&Some(ref node) => { 1 + recurse(&node.child_l) + recurse(&node.child_r) }
&None => 0
}
}
1 + recurse(&self.child_l) + recurse(&self.child_r)
}
}
impl<T:Show, K:BitArray> PatriciaTree<T, K> {
/// Print the entire tree
pub fn print<'a>(&'a self) {
fn recurse<'a, T:Show, K:BitArray>(tree: &'a PatriciaTree<T, K>, depth: uint) {
for i in range(0, tree.skip_len as uint) {
print!("{:}", if tree.skip_prefix.bit(i) { 1u } else { 0 });
}
println!(": {:}", tree.data);
// left gets no indentation
match tree.child_l {
Some(ref t) => {
for _ in range(0, depth + tree.skip_len as uint) {
print!("-");
}
print!("0");
recurse(&**t, depth + tree.skip_len as uint + 1);
}
None => { }
}
// right one gets indentation
match tree.child_r {
Some(ref t) => {
for _ in range(0, depth + tree.skip_len as uint) {
print!("_");
}
print!("1");
recurse(&**t, depth + tree.skip_len as uint + 1);
}
None => { }
}
}
recurse(self, 0);
}
}
impl<T:Serializable+'static, K:BitArray+Serializable+'static> Serializable for PatriciaTree<T, K> {
fn serialize(&self) -> Vec<u8> {
// Depth-first serialization
let mut ret = vec![];
// Serialize self, then children
ret.extend(self.skip_prefix.serialize().move_iter());
ret.extend(self.skip_len.serialize().move_iter());
ret.extend(self.data.serialize().move_iter());
ret.extend(self.child_l.serialize().move_iter());
ret.extend(self.child_r.serialize().move_iter());
ret
}
fn serialize_iter<'a>(&'a self) -> SerializeIter<'a> {
SerializeIter {
data_iter: None,
sub_iter_iter: box vec![ &self.skip_prefix as &Serializable,
&self.skip_len as &Serializable,
&self.data as &Serializable,
&self.child_l as &Serializable,
&self.child_r as &Serializable ].move_iter(),
sub_iter: None,
sub_started: false
}
}
fn deserialize<I: Iterator<u8>>(mut iter: I) -> IoResult<PatriciaTree<T, K>> {
// This goofy deserialization routine is to prevent an infinite
// regress of ByRef<ByRef<...<ByRef<I>>...>>, see #15188
fn recurse<T:Serializable, K:Serializable, I: Iterator<u8>>(iter: &mut ByRef<I>) -> IoResult<PatriciaTree<T, K>> {
Ok(PatriciaTree {
skip_prefix: try!(prepend_err("skip_prefix", Serializable::deserialize(iter.by_ref()))),
skip_len: try!(prepend_err("skip_len", Serializable::deserialize(iter.by_ref()))),
data: try!(prepend_err("data", Serializable::deserialize(iter.by_ref()))),
child_l: match iter.next() {
Some(1) => Some(box try!(prepend_err("child_l", recurse(iter)))),
Some(0) => None,
_ => { return Err(standard_error(InvalidInput)) }
},
child_r: match iter.next() {
Some(1) => Some(box try!(prepend_err("child_r", recurse(iter)))),
Some(0) => None,
_ => { return Err(standard_error(InvalidInput)) }
}
})
}
recurse(&mut iter.by_ref())
}
}
#[cfg(test)]
mod tests {
use std::prelude::*;
use std::io::IoResult;
use std::num::Zero;
use util::hash::Sha256dHash;
use util::uint::Uint128;
use util::uint::Uint256;
use util::patricia_tree::PatriciaTree;
use network::serialize::Serializable;
#[test]
fn patricia_single_insert_lookup_delete_test() {
let mut key: Uint256 = FromPrimitive::from_u64(0xDEADBEEFDEADBEEF).unwrap();
key = key + (key << 64);
let mut tree = PatriciaTree::new();
tree.insert(&key, 100, 100u32);
tree.insert(&key, 120, 100u32);
assert_eq!(tree.lookup(&key, 100), Some(&100u32));
assert_eq!(tree.lookup(&key, 101), None);
assert_eq!(tree.lookup(&key, 99), None);
assert_eq!(tree.delete(&key, 100), Some(100u32));
}
#[test]
fn patricia_insert_lookup_delete_test() {
let mut tree = PatriciaTree::new();
let mut hashes = vec![];
for i in range(0u32, 5000) {
let hash = Sha256dHash::from_data(&[(i / 0x100) as u8, (i % 0x100) as u8]).as_uint128();
tree.insert(&hash, 250, i);
hashes.push(hash);
}
// Check that all inserts are correct
for (n, hash) in hashes.iter().enumerate() {
let ii = n as u32;
let ret = tree.lookup(hash, 250);
assert_eq!(ret, Some(&ii));
}
// Delete all the odd-numbered nodes
for (n, hash) in hashes.iter().enumerate() {
if n % 2 == 1 {
let ii = n as u32;
let ret = tree.delete(hash, 250);
assert_eq!(ret, Some(ii));
}
}
// Confirm all is correct
for (n, hash) in hashes.iter().enumerate() {
let ii = n as u32;
let ret = tree.lookup(hash, 250);
if n % 2 == 0 {
assert_eq!(ret, Some(&ii));
} else {
assert_eq!(ret, None);
}
}
}
#[test]
fn patricia_insert_substring_keys() {
// This test uses a bunch of keys that are substrings of each other
// to make sure insertion and deletion does not lose data
let mut tree = PatriciaTree::new();
let mut hashes = vec![];
// Start by inserting a bunch of chunder
for i in range(1u32, 500) {
let hash = Sha256dHash::from_data(&[(i / 0x100) as u8, (i % 0x100) as u8]).as_uint128();
tree.insert(&hash, 128, i * 1000);
hashes.push(hash);
}
// Do the actual test -- note that we also test insertion and deletion
// at the root here.
for i in range(0u32, 10) {
tree.insert(&Zero::zero(), i as uint, i);
}
for i in range(0u32, 10) {
let m = tree.lookup(&Zero::zero(), i as uint);
assert_eq!(m, Some(&i));
}
for i in range(0u32, 10) {
let m = tree.delete(&Zero::zero(), i as uint);
assert_eq!(m, Some(i));
}
// Check that the chunder was unharmed
for (n, hash) in hashes.iter().enumerate() {
let ii = ((n + 1) * 1000) as u32;
let ret = tree.lookup(hash, 128);
assert_eq!(ret, Some(&ii));
}
}
#[test]
fn patricia_serialize_test() {
// Build a tree
let mut tree = PatriciaTree::new();
let mut hashes = vec![];
for i in range(0u32, 5000) {
let hash = Sha256dHash::from_data(&[(i / 0x100) as u8, (i % 0x100) as u8]).as_uint128();
tree.insert(&hash, 250, i);
hashes.push(hash);
}
// Serialize it
let serialized = tree.serialize();
// Check iterator
let serialized_1 = tree.serialize_iter().collect();
assert_eq!(serialized, serialized_1);
// Deserialize it
let deserialized: IoResult<PatriciaTree<u32, Uint128>> = Serializable::deserialize(serialized.iter().map(|n| *n));
assert!(deserialized.is_ok());
let new_tree = deserialized.unwrap();
// Check that all inserts are still there
for (n, hash) in hashes.iter().enumerate() {
let ii = n as u32;
let ret = new_tree.lookup(hash, 250);
assert_eq!(ret, Some(&ii));
}
}
}

265
src/util/thinvec.rs Normal file
View File

@ -0,0 +1,265 @@
// 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/>.
//
//! # Thin vectors
//!
//! A vector type designed to take as little memory as possible by limiting
//! its size to 4bn elements and not distinguishing between size and capacity.
//! It is very easy to read uninitialized memory: make sure you assign all
//! values after calling `reserve` or `with_capacity`.
//!
use alloc::heap::{allocate, reallocate, deallocate};
use std::raw::Slice;
use std::slice::Items;
use std::{fmt, mem, ptr};
use std::u32;
/// A vector type designed to take very little memory
pub struct ThinVec<T> {
ptr: *mut T,
cap: u32 // capacity and length are the same
}
impl<T> ThinVec<T> {
/// Constructor
#[inline]
pub fn new() -> ThinVec<T> { ThinVec { ptr: RawPtr::null(), cap: 0 } }
/// Constructor with predetermined capacity
#[inline]
pub fn with_capacity(capacity: u32) -> ThinVec<T> {
if mem::size_of::<T>() == 0 {
ThinVec { ptr: RawPtr::null(), cap: capacity }
} else if capacity == 0 {
ThinVec::new()
} else {
let size = (capacity as uint).checked_mul(&mem::size_of::<T>())
.expect("ThinVec::reserve: capacity overflow");
let ptr = unsafe { allocate(size, mem::min_align_of::<T>()) };
ThinVec { ptr: ptr as *mut T, cap: capacity }
}
}
/// Iterator over elements of the vector
#[inline]
pub fn iter<'a>(&'a self) -> Items<'a, T> {
self.as_slice().iter()
}
/// Get vector as mutable slice
#[inline]
pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
unsafe { mem::transmute(Slice { data: self.ptr as *const T, len: self.cap as uint }) }
}
/// Accessor
#[inline]
pub unsafe fn get<'a>(&'a self, index: uint) -> &'a T {
&self.as_slice()[index]
}
/// Mutable accessor NOT for first use
#[inline]
pub unsafe fn get_mut<'a>(&'a mut self, index: uint) -> &'a mut T {
&mut self.as_mut_slice()[index]
}
/// Mutable accessor for first use
#[inline]
pub unsafe fn init<'a>(&'a mut self, index: uint, value: T) {
ptr::write(&mut *self.ptr.offset(index as int), value);
}
/// Push: always reallocates, try not to use this
#[inline]
pub fn push(&mut self, value: T) {
self.cap = self.cap.checked_add(&1).expect("ThinVec::push: length overflow");
if mem::size_of::<T>() == 0 {
unsafe { mem::forget(value); }
} else {
let old_size = (self.cap - 1) as uint * mem::size_of::<T>();
let new_size = self.cap as uint * mem::size_of::<T>();
if new_size < old_size { fail!("ThinVec::push: cap overflow") }
unsafe {
self.ptr =
if old_size == 0 {
allocate(new_size, mem::min_align_of::<T>()) as *mut T
} else {
reallocate(self.ptr as *mut u8, new_size,
mem::min_align_of::<T>(), self.cap as uint) as *mut T
};
ptr::write(&mut *self.ptr.offset((self.cap - 1) as int), value);
}
}
}
/// Set the length of the vector to the minimum of the current capacity and new capacity
pub fn reserve(&mut self, new_cap: u32) {
if new_cap > self.cap {
let new_size = (new_cap as uint).checked_mul(&mem::size_of::<T>())
.expect("ThinVec::reserve: capacity overflow");
unsafe {
self.ptr =
if self.cap == 0 {
allocate(new_size, mem::min_align_of::<T>()) as *mut T
} else {
reallocate(self.ptr as *mut u8, new_size,
mem::min_align_of::<T>(), self.cap as uint) as *mut T
};
}
self.cap = new_cap;
}
}
/// Increase the length of the vector
pub fn reserve_additional(&mut self, extra: u32) {
let new_cap = self.cap.checked_add(&extra).expect("ThinVec::reserve_additional: length overflow");
self.reserve(new_cap);
}
}
impl<T:Clone> ThinVec<T> {
/// Push an entire slice onto the ThinVec
#[inline]
pub fn push_all(&mut self, other: &[T]) {
let old_cap = self.cap as uint;
self.reserve_additional(other.len() as u32);
// Copied from vec.rs, which claims this will be optimized to a memcpy
// if T is Copy
for i in range(0, other.len()) {
unsafe {
ptr::write(self.as_mut_slice().unsafe_mut_ref(old_cap + i),
other.unsafe_ref(i).clone());
}
}
}
}
impl<T> Vector<T> for ThinVec<T> {
#[inline]
fn as_slice<'a>(&'a self) -> &'a [T] {
unsafe { mem::transmute(Slice { data: self.ptr as *const T, len: self.cap as uint }) }
}
}
impl<T:Clone> Clone for ThinVec<T> {
fn clone(&self) -> ThinVec<T> {
let mut ret = ThinVec::with_capacity(self.len() as u32);
// Copied from vec.rs, which claims this will be optimized to a memcpy
// if T is Copy
for i in range(0, self.len()) {
unsafe {
ptr::write(ret.as_mut_slice().unsafe_mut_ref(i),
self.as_slice().unsafe_ref(i).clone());
}
}
ret
}
// TODO: clone_from
}
impl<T> FromIterator<T> for ThinVec<T> {
#[inline]
fn from_iter<I: Iterator<T>>(iter: I) -> ThinVec<T> {
let (lower, _) = iter.size_hint();
assert!(lower < u32::MAX as uint);
let mut vector = ThinVec::with_capacity(lower as u32);
for (n, elem) in iter.enumerate() {
if n < lower {
unsafe { vector.init(n, elem) };
} else {
vector.push(elem);
}
}
vector
}
}
impl<T> Extendable<T> for ThinVec<T> {
#[inline]
fn extend<I: Iterator<T>>(&mut self, iter: I) {
let old_cap = self.cap;
let (lower, _) = iter.size_hint();
self.reserve_additional(lower as u32);
for (n, elem) in iter.enumerate() {
if n < lower {
unsafe { self.init(old_cap as uint + n, elem) };
} else {
self.push(elem);
}
}
}
}
impl<T> Collection for ThinVec<T> {
#[inline]
fn len(&self) -> uint { self.cap as uint }
}
impl<T:fmt::Show> fmt::Show for ThinVec<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.as_slice().fmt(f)
}
}
impl<T: PartialEq> PartialEq for ThinVec<T> {
#[inline]
fn eq(&self, other: &ThinVec<T>) -> bool {
self.as_slice() == other.as_slice()
}
}
impl<T: Eq> Eq for ThinVec<T> {}
#[unsafe_destructor]
impl<T> Drop for ThinVec<T> {
fn drop(&mut self) {
if self.cap != 0 {
unsafe {
for x in self.as_mut_slice().iter() {
ptr::read(x);
}
if mem::size_of::<T>() != 0 {
deallocate(self.ptr as *mut u8,
self.cap as uint * mem::size_of::<T>(),
mem::min_align_of::<T>());
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::ThinVec;
#[test]
fn simple_destructor_thinvec_test() {
let cap = 2;
let mut thinvec = ThinVec::with_capacity(cap);
for i in range(0, cap) {
unsafe { thinvec.init(i as uint, Some(box i)); }
}
for i in range(0, cap) {
unsafe {
assert_eq!(thinvec.get_mut(i as uint).take(), Some(box i));
assert_eq!(thinvec.get_mut(i as uint).take(), None);
}
}
}
}

483
src/util/uint.rs Normal file
View File

@ -0,0 +1,483 @@
// 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/>.
//
//! # Big unsigned integer types
//!
//! Implementation of a various large-but-fixed sized unsigned integer types.
//! The functions here are designed to be fast.
//!
use std::fmt;
use std::io::IoResult;
use std::num::{Zero, One};
use std::mem::transmute;
use network::serialize::Serializable;
use util::BitArray;
macro_rules! construct_uint(
($name:ident, $n_words:expr) => (
/// Little-endian large integer type
#[repr(C)]
pub struct $name(pub [u64, ..$n_words]);
impl $name {
/// Conversion to u32
#[inline]
pub fn low_u32(&self) -> u32 {
let &$name(ref arr) = self;
arr[0] as u32
}
/// Return the least number of bits needed to represent the number
#[inline]
pub fn bits(&self) -> uint {
let &$name(ref arr) = self;
for i in range(1u, $n_words) {
if arr[$n_words - i] > 0 { return (0x40 * ($n_words - i + 1)) - arr[$n_words - i].leading_zeros() as uint; }
}
0x40 - arr[0].leading_zeros() as uint
}
/// Multiplication by u32
pub fn mul_u32(&self, other: u32) -> $name {
let &$name(ref arr) = self;
let mut carry = [0u64, ..$n_words];
let mut ret = [0u64, ..$n_words];
for i in range(0u, $n_words) {
let upper = other as u64 * (arr[i] >> 32);
let lower = other as u64 * (arr[i] & 0xFFFFFFFF);
if i < 3 {
carry[i + 1] += upper >> 32;
}
ret[i] = lower + (upper << 32);
}
$name(ret) + $name(carry)
}
}
impl FromPrimitive for $name {
#[inline]
fn from_u64(init: u64) -> Option<$name> {
let mut ret = [0, ..$n_words];
ret[0] = init;
Some($name(ret))
}
#[inline]
fn from_i64(init: i64) -> Option<$name> {
FromPrimitive::from_u64(init as u64)
}
}
impl Zero for $name {
fn zero() -> $name { $name([0, ..$n_words]) }
fn is_zero(&self) -> bool { *self == Zero::zero() }
}
impl One for $name {
fn one() -> $name {
$name({ let mut ret = [0, ..$n_words]; ret[0] = 1; ret })
}
}
impl Add<$name,$name> for $name {
fn add(&self, other: &$name) -> $name {
let &$name(ref me) = self;
let &$name(ref you) = other;
let mut ret = [0u64, ..$n_words];
let mut carry = [0u64, ..$n_words];
let mut b_carry = false;
for i in range(0u, $n_words) {
ret[i] = me[i] + you[i];
if i < $n_words - 1 && ret[i] < me[i] {
carry[i + 1] = 1;
b_carry = true;
}
}
if b_carry { $name(ret) + $name(carry) } else { $name(ret) }
}
}
impl Sub<$name,$name> for $name {
#[inline]
fn sub(&self, other: &$name) -> $name {
*self + !*other + One::one()
}
}
impl Mul<$name,$name> for $name {
fn mul(&self, other: &$name) -> $name {
let mut me = *self;
// TODO: be more efficient about this
for i in range(0u, 2 * $n_words) {
me = me + me.mul_u32((other >> (32 * i)).low_u32()) << (32 * i);
}
me
}
}
impl Div<$name,$name> for $name {
fn div(&self, other: &$name) -> $name {
let mut sub_copy = *self;
let mut shift_copy = *other;
let mut ret = [0u64, ..$n_words];
let my_bits = self.bits();
let your_bits = other.bits();
// Check for division by 0
assert!(your_bits != 0);
// Early return in case we are dividing by a larger number than us
if my_bits < your_bits {
return $name(ret);
}
// Bitwise long division
let mut shift = my_bits - your_bits;
shift_copy = shift_copy << shift;
loop {
if sub_copy >= shift_copy {
ret[shift / 64] |= 1 << (shift % 64);
sub_copy = sub_copy.sub(&shift_copy);
}
shift_copy = shift_copy >> 1;
if shift == 0 { break; }
shift -= 1;
}
$name(ret)
}
}
impl BitArray for $name {
#[inline]
fn bit(&self, index: uint) -> bool {
let &$name(ref arr) = self;
arr[index / 64] & (1 << (index % 64)) != 0
}
#[inline]
fn bit_slice(&self, start: uint, end: uint) -> $name {
(self >> start).mask(end - start)
}
#[inline]
fn mask(&self, n: uint) -> $name {
let &$name(ref arr) = self;
let mut ret = [0, ..$n_words];
for i in range(0u, $n_words) {
if n >= 0x40 * (i + 1) {
ret[i] = arr[i];
} else {
ret[i] = arr[i] & ((1 << (n - 0x40 * i)) - 1);
break;
}
}
$name(ret)
}
#[inline]
fn trailing_zeros(&self) -> uint {
let &$name(ref arr) = self;
for i in range(0u, $n_words - 1) {
if arr[i] > 0 { return (0x40 * i) + arr[i].trailing_zeros() as uint; }
}
(0x40 * ($n_words - 1)) + arr[3].trailing_zeros() as uint
}
}
impl BitAnd<$name,$name> for $name {
#[inline]
fn bitand(&self, other: &$name) -> $name {
let &$name(ref arr1) = self;
let &$name(ref arr2) = other;
let mut ret = [0u64, ..$n_words];
for i in range(0u, $n_words) {
ret[i] = arr1[i] & arr2[i];
}
$name(ret)
}
}
impl BitXor<$name,$name> for $name {
#[inline]
fn bitxor(&self, other: &$name) -> $name {
let &$name(ref arr1) = self;
let &$name(ref arr2) = other;
let mut ret = [0u64, ..$n_words];
for i in range(0u, $n_words) {
ret[i] = arr1[i] ^ arr2[i];
}
$name(ret)
}
}
impl BitOr<$name,$name> for $name {
#[inline]
fn bitor(&self, other: &$name) -> $name {
let &$name(ref arr1) = self;
let &$name(ref arr2) = other;
let mut ret = [0u64, ..$n_words];
for i in range(0u, $n_words) {
ret[i] = arr1[i] | arr2[i];
}
$name(ret)
}
}
impl Not<$name> for $name {
#[inline]
fn not(&self) -> $name {
let &$name(ref arr) = self;
let mut ret = [0u64, ..$n_words];
for i in range(0u, $n_words) {
ret[i] = !arr[i];
}
$name(ret)
}
}
impl Shl<uint,$name> for $name {
fn shl(&self, shift: &uint) -> $name {
let &$name(ref original) = self;
let mut ret = [0u64, ..$n_words];
let word_shift = *shift / 64;
let bit_shift = *shift % 64;
for i in range(0u, $n_words) {
// Shift
if bit_shift < 64 && i + word_shift < $n_words {
ret[i + word_shift] += original[i] << bit_shift;
}
// Carry
if bit_shift > 0 && i + word_shift + 1 < $n_words {
ret[i + word_shift + 1] += original[i] >> (64 - bit_shift);
}
}
$name(ret)
}
}
impl Shr<uint,$name> for $name {
#[allow(unsigned_negate)]
fn shr(&self, shift: &uint) -> $name {
let &$name(ref original) = self;
let mut ret = [0u64, ..$n_words];
let word_shift = *shift / 64;
let bit_shift = *shift % 64;
for i in range(0u, $n_words) {
// Shift
if bit_shift < 64 && i - word_shift < $n_words {
ret[i - word_shift] += original[i] >> bit_shift;
}
// Carry
if bit_shift > 0 && i - word_shift - 1 < $n_words {
ret[i - word_shift - 1] += original[i] << (64 - bit_shift);
}
}
$name(ret)
}
}
impl PartialEq for $name {
fn eq(&self, other: &$name) -> bool {
let &$name(ref arr1) = self;
let &$name(ref arr2) = other;
for i in range(0, $n_words) {
if arr1[i] != arr2[i] { return false; }
}
return true;
}
}
impl Eq for $name {}
impl Ord for $name {
fn cmp(&self, other: &$name) -> Ordering {
let &$name(ref me) = self;
let &$name(ref you) = other;
for i in range(0, $n_words) {
if me[3 - i] < you[3 - i] { return Less; }
if me[3 - i] > you[3 - i] { return Greater; }
}
return Equal;
}
}
impl PartialOrd for $name {
fn partial_cmp(&self, other: &$name) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl fmt::Show for $name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.serialize().as_slice())
}
}
impl Serializable for $name {
fn serialize(&self) -> Vec<u8> {
let vec = unsafe { transmute::<$name, [u8, ..($n_words*8)]>(*self) };
vec.serialize()
}
fn deserialize<I: Iterator<u8>>(mut iter: I) -> IoResult<$name> {
let ret: [u8, ..($n_words*8)] = try!(Serializable::deserialize(iter.by_ref()));
Ok(unsafe { transmute(ret) })
}
}
);
)
construct_uint!(Uint256, 4)
construct_uint!(Uint128, 2)
impl Uint256 {
/// Increment by 1
#[inline]
pub fn increment(&mut self) {
let &Uint256(ref mut arr) = self;
arr[0] += 1;
if arr[0] == 0 {
arr[1] += 1;
if arr[1] == 0 {
arr[2] += 1;
if arr[2] == 0 {
arr[3] += 1;
}
}
}
}
}
#[cfg(test)]
mod tests {
use std::io::IoResult;
use std::num::from_u64;
use network::serialize::Serializable;
use util::uint::Uint256;
use util::BitArray;
#[test]
pub fn uint256_bits_test() {
assert_eq!(from_u64::<Uint256>(255).unwrap().bits(), 8);
assert_eq!(from_u64::<Uint256>(256).unwrap().bits(), 9);
assert_eq!(from_u64::<Uint256>(300).unwrap().bits(), 9);
assert_eq!(from_u64::<Uint256>(60000).unwrap().bits(), 16);
assert_eq!(from_u64::<Uint256>(70000).unwrap().bits(), 17);
// Try to read the following lines out loud quickly
let mut shl: Uint256 = from_u64(70000).unwrap();
shl = shl << 100u;
assert_eq!(shl.bits(), 117);
shl = shl << 100u;
assert_eq!(shl.bits(), 217);
shl = shl << 100u;
assert_eq!(shl.bits(), 0);
// Bit set check
assert!(!from_u64::<Uint256>(10).unwrap().bit(0));
assert!(from_u64::<Uint256>(10).unwrap().bit(1));
assert!(!from_u64::<Uint256>(10).unwrap().bit(2));
assert!(from_u64::<Uint256>(10).unwrap().bit(3));
assert!(!from_u64::<Uint256>(10).unwrap().bit(4));
}
#[test]
pub fn uint256_comp_test() {
let small = Uint256([10u64, 0, 0, 0]);
let big = Uint256([0x8C8C3EE70C644118u64, 0x0209E7378231E632, 0, 0]);
let bigger = Uint256([0x9C8C3EE70C644118u64, 0x0209E7378231E632, 0, 0]);
let biggest = Uint256([0x5C8C3EE70C644118u64, 0x0209E7378231E632, 0, 1]);
assert!(small < big);
assert!(big < bigger);
assert!(bigger < biggest);
assert!(bigger <= biggest);
assert!(biggest <= biggest);
assert!(bigger >= big);
assert!(bigger >= small);
assert!(small <= small);
}
#[test]
pub fn uint256_arithmetic_test() {
let init: Uint256 = from_u64(0xDEADBEEFDEADBEEF).unwrap();
let copy = init;
let add = init.add(&copy);
assert_eq!(add, Uint256([0xBD5B7DDFBD5B7DDEu64, 1, 0, 0]));
// Bitshifts
let shl = add << 88u;
assert_eq!(shl, Uint256([0u64, 0xDFBD5B7DDE000000, 0x1BD5B7D, 0]));
let shr = shl >> 40u;
assert_eq!(shr, Uint256([0x7DDE000000000000u64, 0x0001BD5B7DDFBD5B, 0, 0]));
// Increment
let mut incr = shr;
incr.increment();
assert_eq!(incr, Uint256([0x7DDE000000000001u64, 0x0001BD5B7DDFBD5B, 0, 0]));
// Subtraction
let sub = incr.sub(&init);
assert_eq!(sub, Uint256([0x9F30411021524112u64, 0x0001BD5B7DDFBD5A, 0, 0]));
// Multiplication
let mult = sub.mul_u32(300);
assert_eq!(mult, Uint256([0x8C8C3EE70C644118u64, 0x0209E7378231E632, 0, 0]));
// Division
assert_eq!(from_u64::<Uint256>(105).unwrap() /
from_u64::<Uint256>(5).unwrap(),
from_u64::<Uint256>(21).unwrap());
let div = mult / from_u64::<Uint256>(300).unwrap();
assert_eq!(div, Uint256([0x9F30411021524112u64, 0x0001BD5B7DDFBD5A, 0, 0]));
// TODO: bit inversion
}
#[test]
pub fn uint256_bitslice_test() {
let init = from_u64::<Uint256>(0xDEADBEEFDEADBEEF).unwrap();
let add = init + (init << 64);
assert_eq!(add.bit_slice(64, 128), init);
assert_eq!(add.mask(64), init);
}
#[test]
pub fn uint256_extreme_bitshift_test() {
// Shifting a u64 by 64 bits gives an undefined value, so make sure that
// we're doing the Right Thing here
let init = from_u64::<Uint256>(0xDEADBEEFDEADBEEF).unwrap();
assert_eq!(init << 64, Uint256([0, 0xDEADBEEFDEADBEEF, 0, 0]));
let add = (init << 64).add(&init);
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 >> 64, Uint256([0xDEADBEEFDEADBEEF, 0, 0, 0]));
assert_eq!(add << 64, Uint256([0, 0xDEADBEEFDEADBEEF, 0xDEADBEEFDEADBEEF, 0]));
}
#[test]
pub fn uint256_serialize_test() {
let start1 = Uint256([0x8C8C3EE70C644118u64, 0x0209E7378231E632, 0, 0]);
let start2 = Uint256([0x8C8C3EE70C644118u64, 0x0209E7378231E632, 0xABCD, 0xFFFF]);
let serial1 = start1.serialize();
let serial2 = start2.serialize();
let end1: IoResult<Uint256> = Serializable::deserialize(serial1.iter().map(|n| *n));
let end2: IoResult<Uint256> = Serializable::deserialize(serial2.iter().map(|n| *n));
assert_eq!(end1, Ok(start1));
assert_eq!(end2, Ok(start2));
}
}