More changes, incl. dropping DumbHasher in favor of SipHasher
only json stuff left in this round of compiler errors :)
This commit is contained in:
parent
7738722ab5
commit
7b89c15ed5
|
@ -23,13 +23,13 @@
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use std::num::Zero;
|
use std::num::Zero;
|
||||||
use std::{marker, ptr};
|
use std::{marker, num, ptr};
|
||||||
|
|
||||||
use blockdata::block::{Block, BlockHeader};
|
use blockdata::block::{Block, BlockHeader};
|
||||||
use blockdata::transaction::Transaction;
|
use blockdata::transaction::Transaction;
|
||||||
use blockdata::constants::{DIFFCHANGE_INTERVAL, DIFFCHANGE_TIMESPAN,
|
use blockdata::constants::{DIFFCHANGE_INTERVAL, DIFFCHANGE_TIMESPAN,
|
||||||
TARGET_BLOCK_SPACING, max_target, genesis_block};
|
TARGET_BLOCK_SPACING, max_target, genesis_block};
|
||||||
use network::constants::Network::{self, BitcoinTestnet};
|
use network::constants::Network;
|
||||||
use network::encodable::{ConsensusDecodable, ConsensusEncodable};
|
use network::encodable::{ConsensusDecodable, ConsensusEncodable};
|
||||||
use network::serialize::{BitcoinHash, SimpleDecoder, SimpleEncoder};
|
use network::serialize::{BitcoinHash, SimpleDecoder, SimpleEncoder};
|
||||||
use util::BitArray;
|
use util::BitArray;
|
||||||
|
@ -462,7 +462,7 @@ impl Blockchain {
|
||||||
// Compute new target
|
// Compute new target
|
||||||
let mut target = unsafe { (*prev).block.header.target() };
|
let mut target = unsafe { (*prev).block.header.target() };
|
||||||
target = target.mul_u32(timespan);
|
target = target.mul_u32(timespan);
|
||||||
target = target / FromPrimitive::from_u64(DIFFCHANGE_TIMESPAN as u64).unwrap();
|
target = target / num::FromPrimitive::from_u64(DIFFCHANGE_TIMESPAN as u64).unwrap();
|
||||||
// Clamp below MAX_TARGET (difficulty 1)
|
// Clamp below MAX_TARGET (difficulty 1)
|
||||||
let max = max_target(self.network);
|
let max = max_target(self.network);
|
||||||
if target > max { target = max };
|
if target > max { target = max };
|
||||||
|
@ -470,13 +470,13 @@ impl Blockchain {
|
||||||
satoshi_the_precision(&target)
|
satoshi_the_precision(&target)
|
||||||
// On non-diffchange blocks, Testnet has a rule that any 20-minute-long
|
// On non-diffchange blocks, Testnet has a rule that any 20-minute-long
|
||||||
// block intervals result the difficulty
|
// block intervals result the difficulty
|
||||||
} else if self.network == BitcoinTestnet &&
|
} else if self.network == Network::BitcoinTestnet &&
|
||||||
block.header.time > unsafe { (*prev).block.header.time } + 2*TARGET_BLOCK_SPACING {
|
block.header.time > unsafe { (*prev).block.header.time } + 2*TARGET_BLOCK_SPACING {
|
||||||
max_target(self.network)
|
max_target(self.network)
|
||||||
// On the other hand, if we are in Testnet and the block interval is less
|
// On the other hand, if we are in Testnet and the block interval is less
|
||||||
// than 20 minutes, we need to scan backward to find a block for which the
|
// than 20 minutes, we need to scan backward to find a block for which the
|
||||||
// previous rule did not apply, to find the "real" difficulty.
|
// previous rule did not apply, to find the "real" difficulty.
|
||||||
} else if self.network == BitcoinTestnet {
|
} else if self.network == Network::BitcoinTestnet {
|
||||||
// Scan back DIFFCHANGE_INTERVAL blocks
|
// Scan back DIFFCHANGE_INTERVAL blocks
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut scan = prev;
|
let mut scan = prev;
|
||||||
|
|
|
@ -26,7 +26,7 @@ use blockdata::opcodes;
|
||||||
use blockdata::script::Script;
|
use blockdata::script::Script;
|
||||||
use blockdata::transaction::{Transaction, TxOut, TxIn};
|
use blockdata::transaction::{Transaction, TxOut, TxIn};
|
||||||
use blockdata::block::{Block, BlockHeader};
|
use blockdata::block::{Block, BlockHeader};
|
||||||
use network::constants::Network::{Bitcoin, BitcoinTestnet};
|
use network::constants::Network;
|
||||||
use util::misc::hex_bytes;
|
use util::misc::hex_bytes;
|
||||||
use util::hash::MerkleRoot;
|
use util::hash::MerkleRoot;
|
||||||
use util::uint::Uint256;
|
use util::uint::Uint256;
|
||||||
|
@ -74,7 +74,7 @@ fn bitcoin_genesis_tx() -> Transaction {
|
||||||
// Outputs
|
// Outputs
|
||||||
let mut out_script = Script::new();
|
let mut out_script = Script::new();
|
||||||
out_script.push_slice(hex_bytes("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f").unwrap().as_slice());
|
out_script.push_slice(hex_bytes("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f").unwrap().as_slice());
|
||||||
out_script.push_opcode(opcodes::all::OP_CHECKSIG);
|
out_script.push_opcode(opcodes::All::OP_CHECKSIG);
|
||||||
ret.output.push(TxOut {
|
ret.output.push(TxOut {
|
||||||
value: 50 * COIN_VALUE,
|
value: 50 * COIN_VALUE,
|
||||||
script_pubkey: out_script
|
script_pubkey: out_script
|
||||||
|
@ -87,7 +87,7 @@ fn bitcoin_genesis_tx() -> Transaction {
|
||||||
/// Constructs and returns the genesis block
|
/// Constructs and returns the genesis block
|
||||||
pub fn genesis_block(network: Network) -> Block {
|
pub fn genesis_block(network: Network) -> Block {
|
||||||
match network {
|
match network {
|
||||||
Bitcoin => {
|
Network::Bitcoin => {
|
||||||
let txdata = vec![bitcoin_genesis_tx()];
|
let txdata = vec![bitcoin_genesis_tx()];
|
||||||
Block {
|
Block {
|
||||||
header: BlockHeader {
|
header: BlockHeader {
|
||||||
|
@ -101,7 +101,7 @@ pub fn genesis_block(network: Network) -> Block {
|
||||||
txdata: txdata
|
txdata: txdata
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BitcoinTestnet => {
|
Network::Testnet => {
|
||||||
let txdata = vec![bitcoin_genesis_tx()];
|
let txdata = vec![bitcoin_genesis_tx()];
|
||||||
Block {
|
Block {
|
||||||
header: BlockHeader {
|
header: BlockHeader {
|
||||||
|
@ -123,7 +123,7 @@ mod test {
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use serialize::hex::FromHex;
|
use serialize::hex::FromHex;
|
||||||
|
|
||||||
use network::constants::Network::{Bitcoin, BitcoinTestnet};
|
use network::constants::Network;
|
||||||
use network::serialize::{BitcoinHash, serialize};
|
use network::serialize::{BitcoinHash, serialize};
|
||||||
use blockdata::constants::{genesis_block, bitcoin_genesis_tx};
|
use blockdata::constants::{genesis_block, bitcoin_genesis_tx};
|
||||||
use blockdata::constants::{MAX_SEQUENCE, COIN_VALUE};
|
use blockdata::constants::{MAX_SEQUENCE, COIN_VALUE};
|
||||||
|
@ -152,7 +152,7 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bitcoin_genesis_full_block() {
|
fn bitcoin_genesis_full_block() {
|
||||||
let gen = genesis_block(Bitcoin);
|
let gen = genesis_block(network::Bitcoin);
|
||||||
|
|
||||||
assert_eq!(gen.header.version, 1);
|
assert_eq!(gen.header.version, 1);
|
||||||
assert_eq!(gen.header.prev_blockhash, Default::default());
|
assert_eq!(gen.header.prev_blockhash, Default::default());
|
||||||
|
@ -167,7 +167,7 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn testnet_genesis_full_block() {
|
fn testnet_genesis_full_block() {
|
||||||
let gen = genesis_block(BitcoinTestnet);
|
let gen = genesis_block(network::Testnet);
|
||||||
assert_eq!(gen.header.version, 1);
|
assert_eq!(gen.header.version, 1);
|
||||||
assert_eq!(gen.header.prev_blockhash, Default::default());
|
assert_eq!(gen.header.prev_blockhash, Default::default());
|
||||||
assert_eq!(gen.header.merkle_root.be_hex_string(),
|
assert_eq!(gen.header.merkle_root.be_hex_string(),
|
||||||
|
|
|
@ -623,9 +623,9 @@ impl json::ToJson for All {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Empty stack is also FALSE
|
/// Empty stack is also FALSE
|
||||||
pub static OP_FALSE: All = OP_PUSHBYTES_0;
|
pub static OP_FALSE: All = All::OP_PUSHBYTES_0;
|
||||||
/// Number 1 is also TRUE
|
/// Number 1 is also TRUE
|
||||||
pub static OP_TRUE: All = OP_PUSHNUM_1;
|
pub static OP_TRUE: All = All::OP_PUSHNUM_1;
|
||||||
|
|
||||||
/// Broad categories of opcodes with similar behavior
|
/// Broad categories of opcodes with similar behavior
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
|
|
|
@ -50,11 +50,23 @@ use util::misc::script_find_and_remove;
|
||||||
/// A Bitcoin script
|
/// A Bitcoin script
|
||||||
pub struct Script(Box<[u8]>);
|
pub struct Script(Box<[u8]>);
|
||||||
|
|
||||||
impl<S: hash::Writer> hash::Hash<S> for Script {
|
impl hash::Hash for Script {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn hash(&self, state: &mut S) {
|
fn hash<H>(&self, state: &mut H)
|
||||||
|
where H: hash::Hasher
|
||||||
|
{
|
||||||
let &Script(ref raw) = self;
|
let &Script(ref raw) = self;
|
||||||
(&raw[..]).hash(state)
|
(&raw[..]).hash(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn hash_slice<H>(data: &[Script], state: &mut H)
|
||||||
|
where H: hash::Hasher
|
||||||
|
{
|
||||||
|
for s in data.iter() {
|
||||||
|
let &Script(ref raw) = s;
|
||||||
|
(&raw[..]).hash(state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1293,7 +1305,7 @@ impl<'a> ops::Index<ops::Range<usize>> for MaybeOwned<'a> {
|
||||||
type Output = [u8];
|
type Output = [u8];
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index(&self, index: Range<usize>) -> &[u8] {
|
fn index(&self, index: ops::Range<usize>) -> &[u8] {
|
||||||
match *self {
|
match *self {
|
||||||
MaybeOwned::Owned(ref v) => &v[index],
|
MaybeOwned::Owned(ref v) => &v[index],
|
||||||
MaybeOwned::Borrowed(ref s) => &s[index]
|
MaybeOwned::Borrowed(ref s) => &s[index]
|
||||||
|
@ -1305,7 +1317,7 @@ impl<'a> ops::Index<ops::RangeTo<usize>> for MaybeOwned<'a> {
|
||||||
type Output = [u8];
|
type Output = [u8];
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index(&self, index: RangeTo<usize>) -> &[u8] {
|
fn index(&self, index: ops::RangeTo<usize>) -> &[u8] {
|
||||||
match *self {
|
match *self {
|
||||||
MaybeOwned::Owned(ref v) => &v[index],
|
MaybeOwned::Owned(ref v) => &v[index],
|
||||||
MaybeOwned::Borrowed(ref s) => &s[index]
|
MaybeOwned::Borrowed(ref s) => &s[index]
|
||||||
|
@ -1317,7 +1329,7 @@ impl<'a> ops::Index<ops::RangeFrom<usize>> for MaybeOwned<'a> {
|
||||||
type Output = [u8];
|
type Output = [u8];
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index(&self, index: RangeFrom<usize>) -> &[u8] {
|
fn index(&self, index: ops::RangeFrom<usize>) -> &[u8] {
|
||||||
match *self {
|
match *self {
|
||||||
MaybeOwned::Owned(ref v) => &v[index],
|
MaybeOwned::Owned(ref v) => &v[index],
|
||||||
MaybeOwned::Borrowed(ref s) => &s[index]
|
MaybeOwned::Borrowed(ref s) => &s[index]
|
||||||
|
@ -1325,11 +1337,11 @@ impl<'a> ops::Index<ops::RangeFrom<usize>> for MaybeOwned<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ops::Index<ops::RangeAll<usize>> for MaybeOwned<'a> {
|
impl<'a> ops::Index<ops::RangeFull<usize>> for MaybeOwned<'a> {
|
||||||
type Output = [u8];
|
type Output = [u8];
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index(&self, _: RangeAll<usize>) -> &[u8] {
|
fn index(&self, _: ops::RangeFull<usize>) -> &[u8] {
|
||||||
match *self {
|
match *self {
|
||||||
MaybeOwned::Owned(ref v) => &v[..],
|
MaybeOwned::Owned(ref v) => &v[..],
|
||||||
MaybeOwned::Borrowed(ref s) => &s[..]
|
MaybeOwned::Borrowed(ref s) => &s[..]
|
||||||
|
@ -1833,7 +1845,7 @@ impl Script {
|
||||||
// If-statements take effect when not executing
|
// If-statements take effect when not executing
|
||||||
(false, opcodes::Class::Ordinary(opcodes::Ordinary::OP_IF)) => exec_stack.push(false),
|
(false, opcodes::Class::Ordinary(opcodes::Ordinary::OP_IF)) => exec_stack.push(false),
|
||||||
(false, opcodes::Class::Ordinary(opcodes::Ordinary::OP_NOTIF)) => exec_stack.push(false),
|
(false, opcodes::Class::Ordinary(opcodes::Ordinary::OP_NOTIF)) => exec_stack.push(false),
|
||||||
(false, opcodes::Ordinary(opcodes::Ordinary::OP_ELSE)) => {
|
(false, opcodes::Class::Ordinary(opcodes::Ordinary::OP_ELSE)) => {
|
||||||
match exec_stack.last_mut() {
|
match exec_stack.last_mut() {
|
||||||
Some(ref_e) => { *ref_e = !*ref_e }
|
Some(ref_e) => { *ref_e = !*ref_e }
|
||||||
None => { return Err(Error::ElseWithoutIf); }
|
None => { return Err(Error::ElseWithoutIf); }
|
||||||
|
|
|
@ -173,8 +173,8 @@ impl TxIn {
|
||||||
if txo.script_pubkey.is_p2sh() && stack.len() > 0 {
|
if txo.script_pubkey.is_p2sh() && stack.len() > 0 {
|
||||||
p2sh_stack = stack.clone();
|
p2sh_stack = stack.clone();
|
||||||
p2sh_script = match p2sh_stack.pop() {
|
p2sh_script = match p2sh_stack.pop() {
|
||||||
Some(script::Owned(v)) => Script::from_vec(v),
|
Some(script::MaybeOwned::Owned(v)) => Script::from_vec(v),
|
||||||
Some(script::Borrowed(s)) => Script::from_vec(s.to_vec()),
|
Some(script::MaybeOwned::Borrowed(s)) => Script::from_vec(s.to_vec()),
|
||||||
None => unreachable!()
|
None => unreachable!()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -254,8 +254,8 @@ impl Transaction {
|
||||||
if txo.script_pubkey.is_p2sh() && stack.len() > 0 {
|
if txo.script_pubkey.is_p2sh() && stack.len() > 0 {
|
||||||
p2sh_stack = stack.clone();
|
p2sh_stack = stack.clone();
|
||||||
p2sh_script = match p2sh_stack.pop() {
|
p2sh_script = match p2sh_stack.pop() {
|
||||||
Some(script::Owned(v)) => Script::from_vec(v),
|
Some(script::MaybeOwned::Owned(v)) => Script::from_vec(v),
|
||||||
Some(script::Borrowed(s)) => Script::from_vec(s.to_vec()),
|
Some(script::MaybeOwned::Borrowed(s)) => Script::from_vec(s.to_vec()),
|
||||||
None => unreachable!()
|
None => unreachable!()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::collections::hash::map::Iter;
|
use std::collections::hash::map::Iter;
|
||||||
|
use std::hash::SipHasher;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use num_cpus;
|
use num_cpus;
|
||||||
|
@ -31,7 +32,7 @@ use blockdata::constants::genesis_block;
|
||||||
use blockdata::block::Block;
|
use blockdata::block::Block;
|
||||||
use network::constants::Network;
|
use network::constants::Network;
|
||||||
use network::serialize::BitcoinHash;
|
use network::serialize::BitcoinHash;
|
||||||
use util::hash::{DumbHasher, Sha256dHash};
|
use util::hash::Sha256dHash;
|
||||||
|
|
||||||
/// The amount of validation to do when updating the UTXO set
|
/// The amount of validation to do when updating the UTXO set
|
||||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
|
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
|
||||||
|
@ -101,7 +102,7 @@ impl<'a> Iterator<(Sha256dHash, u32, &'a TxOut, u32)> for UtxoIterator<'a> {
|
||||||
|
|
||||||
/// The UTXO set
|
/// The UTXO set
|
||||||
pub struct UtxoSet {
|
pub struct UtxoSet {
|
||||||
table: HashMap<Sha256dHash, UtxoNode, DumbHasher>,
|
table: HashMap<Sha256dHash, UtxoNode, SipHasher>,
|
||||||
last_hash: Sha256dHash,
|
last_hash: Sha256dHash,
|
||||||
// A circular buffer of deleted utxos, grouped by block
|
// A circular buffer of deleted utxos, grouped by block
|
||||||
spent_txos: Vec<Vec<((Sha256dHash, u32), (u32, TxOut))>>,
|
spent_txos: Vec<Vec<((Sha256dHash, u32), (u32, TxOut))>>,
|
||||||
|
@ -121,7 +122,7 @@ impl UtxoSet {
|
||||||
// must follow suit, otherwise we will accept a transaction spending it
|
// must follow suit, otherwise we will accept a transaction spending it
|
||||||
// while the reference client won't, causing us to fork off the network.
|
// while the reference client won't, causing us to fork off the network.
|
||||||
UtxoSet {
|
UtxoSet {
|
||||||
table: HashMap::with_hasher(DumbHasher),
|
table: HashMap::with_hasher(SipHasher::new()),
|
||||||
last_hash: genesis_block(network).header.bitcoin_hash(),
|
last_hash: genesis_block(network).header.bitcoin_hash(),
|
||||||
spent_txos: Vec::from_elem(rewind_limit, vec![]),
|
spent_txos: Vec::from_elem(rewind_limit, vec![]),
|
||||||
spent_idx: 0,
|
spent_idx: 0,
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#![crate_type = "rlib"]
|
#![crate_type = "rlib"]
|
||||||
|
|
||||||
// Experimental features we need
|
// Experimental features we need
|
||||||
|
#![feature(box_patterns)]
|
||||||
#![feature(custom_derive, plugin)]
|
#![feature(custom_derive, plugin)]
|
||||||
#![feature(overloaded_calls)]
|
#![feature(overloaded_calls)]
|
||||||
#![feature(unsafe_destructor)]
|
#![feature(unsafe_destructor)]
|
||||||
|
|
|
@ -28,7 +28,7 @@ user_enum! {
|
||||||
#[doc="Classic Bitcoin"]
|
#[doc="Classic Bitcoin"]
|
||||||
Bitcoin <-> "bitcoin",
|
Bitcoin <-> "bitcoin",
|
||||||
#[doc="Bitcoin's testnet"]
|
#[doc="Bitcoin's testnet"]
|
||||||
BitcoinTestnet <-> "testnet"
|
Testnet <-> "testnet"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ pub const USER_AGENT: &'static str = "bitcoin-rust v0.1";
|
||||||
pub fn magic(network: Network) -> u32 {
|
pub fn magic(network: Network) -> u32 {
|
||||||
match network {
|
match network {
|
||||||
Network::Bitcoin => 0xD9B4BEF9,
|
Network::Bitcoin => 0xD9B4BEF9,
|
||||||
Network::BitcoinTestnet => 0x0709110B
|
Network::Testnet => 0x0709110B
|
||||||
// Note: any new entries here must be added to `deserialize` below
|
// Note: any new entries here must be added to `deserialize` below
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ impl<D:SimpleDecoder<E>, E> ConsensusDecodable<D, E> for Network {
|
||||||
let magic: u32 = try!(ConsensusDecodable::consensus_decode(d));
|
let magic: u32 = try!(ConsensusDecodable::consensus_decode(d));
|
||||||
match magic {
|
match magic {
|
||||||
0xD9B4BEF9 => Ok(Network::Bitcoin),
|
0xD9B4BEF9 => Ok(Network::Bitcoin),
|
||||||
0x0709110B => Ok(Network::BitcoinTestnet),
|
0x0709110B => Ok(Network::Testnet),
|
||||||
x => Err(d.error(format!("Unknown network (magic {:x})", x).as_slice()))
|
x => Err(d.error(format!("Unknown network (magic {:x})", x).as_slice()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,10 +74,10 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_test() {
|
fn serialize_test() {
|
||||||
assert_eq!(serialize(&Network::Bitcoin).unwrap(), vec![0xf9, 0xbe, 0xb4, 0xd9]);
|
assert_eq!(serialize(&Network::Bitcoin).unwrap(), vec![0xf9, 0xbe, 0xb4, 0xd9]);
|
||||||
assert_eq!(serialize(&Network::BitcoinTestnet).unwrap(), vec![0x0b, 0x11, 0x09, 0x07]);
|
assert_eq!(serialize(&Network::Testnet).unwrap(), vec![0x0b, 0x11, 0x09, 0x07]);
|
||||||
|
|
||||||
assert_eq!(deserialize(vec![0xf9, 0xbe, 0xb4, 0xd9]), Ok(Network::Bitcoin));
|
assert_eq!(deserialize(vec![0xf9, 0xbe, 0xb4, 0xd9]), Ok(Network::Bitcoin));
|
||||||
assert_eq!(deserialize(vec![0x0b, 0x11, 0x09, 0x07]), Ok(Network::BitcoinTestnet));
|
assert_eq!(deserialize(vec![0x0b, 0x11, 0x09, 0x07]), Ok(Network::Testnet));
|
||||||
|
|
||||||
let bad: Result<Network, _> = deserialize("fakenet".as_bytes().to_vec());
|
let bad: Result<Network, _> = deserialize("fakenet".as_bytes().to_vec());
|
||||||
assert!(bad.is_err());
|
assert!(bad.is_err());
|
||||||
|
|
|
@ -18,11 +18,11 @@
|
||||||
//! to connect to a peer, send network messages, and receive Bitcoin data.
|
//! to connect to a peer, send network messages, and receive Bitcoin data.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use std::io::{Result, Error, ErrorKind};
|
use std::{io, thread};
|
||||||
|
use std::sync::mpsc::{channel, Receiver};
|
||||||
|
|
||||||
use network::constants::Network;
|
use network::constants::Network;
|
||||||
use network::message;
|
use network::message;
|
||||||
use network::message::SocketResponse::{self, MessageReceived};
|
|
||||||
use network::message::NetworkMessage::Verack;
|
use network::message::NetworkMessage::Verack;
|
||||||
use network::socket::Socket;
|
use network::socket::Socket;
|
||||||
|
|
||||||
|
@ -35,13 +35,13 @@ pub trait Listener {
|
||||||
/// Return the network this `Listener` is operating on
|
/// Return the network this `Listener` is operating on
|
||||||
fn network(&self) -> Network;
|
fn network(&self) -> Network;
|
||||||
/// Main listen loop
|
/// Main listen loop
|
||||||
fn start(&self) -> Result<(Receiver<SocketResponse>, Socket)> {
|
fn start(&self) -> io::Result<(Receiver<message::SocketResponse>, Socket)> {
|
||||||
// Open socket
|
// Open socket
|
||||||
let mut ret_sock = Socket::new(self.network());
|
let mut ret_sock = Socket::new(self.network());
|
||||||
match ret_sock.connect(self.peer(), self.port()) {
|
match ret_sock.connect(self.peer(), self.port()) {
|
||||||
Ok(_) => {},
|
Ok(_) => {},
|
||||||
Err(_) => return Err(Error::new(ErrorKind::ConnectionFailed,
|
Err(_) => return Err(io::Error::new(io::ErrorKind::ConnectionFailed,
|
||||||
"Listener connection failed", None))
|
"Listener connection failed", None))
|
||||||
}
|
}
|
||||||
let mut sock = ret_sock.clone();
|
let mut sock = ret_sock.clone();
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ pub trait Listener {
|
||||||
try!(sock.send_message(version_message));
|
try!(sock.send_message(version_message));
|
||||||
|
|
||||||
// Message loop
|
// Message loop
|
||||||
spawn(move || {
|
thread::spawn(move || {
|
||||||
let mut handshake_complete = false;
|
let mut handshake_complete = false;
|
||||||
let mut sock = sock;
|
let mut sock = sock;
|
||||||
loop {
|
loop {
|
||||||
|
@ -76,7 +76,7 @@ pub trait Listener {
|
||||||
// We have to pass the message to the main thread for processing,
|
// We have to pass the message to the main thread for processing,
|
||||||
// unfortunately, because sipa says we have to handle everything
|
// unfortunately, because sipa says we have to handle everything
|
||||||
// in order.
|
// in order.
|
||||||
recv_tx.send(MessageReceived(payload));
|
recv_tx.send(message::SocketResponse::MessageReceived(payload));
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
// On failure we send an error message to the main thread, along with
|
// On failure we send an error message to the main thread, along with
|
||||||
|
@ -84,7 +84,7 @@ pub trait Listener {
|
||||||
// thread. (If we simply exited immediately, the channel would be torn
|
// thread. (If we simply exited immediately, the channel would be torn
|
||||||
// down and the main thread would never see the error message.)
|
// down and the main thread would never see the error message.)
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
recv_tx.send(message::ConnectionFailed(e, tx));
|
recv_tx.send(message::SocketResponse::ConnectionFailed(e, tx));
|
||||||
rx.recv();
|
rx.recv();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,9 @@
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use collections::Vec;
|
use collections::Vec;
|
||||||
|
use std::iter;
|
||||||
use std::io::{self, Cursor};
|
use std::io::{self, Cursor};
|
||||||
|
use std::sync::mpsc::Sender;
|
||||||
|
|
||||||
use blockdata::block;
|
use blockdata::block;
|
||||||
use blockdata::transaction;
|
use blockdata::transaction;
|
||||||
|
@ -50,7 +52,7 @@ impl<D:SimpleDecoder<E>, E> ConsensusDecodable<D, E> for CommandString {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_decode(d: &mut D) -> Result<CommandString, E> {
|
fn consensus_decode(d: &mut D) -> Result<CommandString, E> {
|
||||||
let rawbytes: [u8; 12] = try!(ConsensusDecodable::consensus_decode(d));
|
let rawbytes: [u8; 12] = try!(ConsensusDecodable::consensus_decode(d));
|
||||||
let rv = FromIterator::from_iter(rawbytes.iter().filter_map(|&u| if u > 0 { Some(u as char) } else { None }));
|
let rv = iter::FromIterator::from_iter(rawbytes.iter().filter_map(|&u| if u > 0 { Some(u as char) } else { None }));
|
||||||
Ok(CommandString(rv))
|
Ok(CommandString(rv))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,11 +27,11 @@ use util::hash::Sha256dHash;
|
||||||
/// The type of an inventory object
|
/// The type of an inventory object
|
||||||
pub enum InvType {
|
pub enum InvType {
|
||||||
/// Error --- these inventories can be ignored
|
/// Error --- these inventories can be ignored
|
||||||
InvError,
|
Error,
|
||||||
/// Transaction
|
/// Transaction
|
||||||
InvTransaction,
|
Transaction,
|
||||||
/// Block
|
/// Block
|
||||||
InvBlock
|
Block
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some simple messages
|
// Some simple messages
|
||||||
|
@ -101,9 +101,9 @@ impl<S:SimpleEncoder<E>, E> ConsensusEncodable<S, E> for Inventory {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_encode(&self, s: &mut S) -> Result<(), E> {
|
fn consensus_encode(&self, s: &mut S) -> Result<(), E> {
|
||||||
try!(match self.inv_type {
|
try!(match self.inv_type {
|
||||||
InvError => 0u32,
|
InvType::Error => 0u32,
|
||||||
InvTransaction => 1,
|
InvType::Transaction => 1,
|
||||||
InvBlock => 2
|
InvType::Block => 2
|
||||||
}.consensus_encode(s));
|
}.consensus_encode(s));
|
||||||
self.hash.consensus_encode(s)
|
self.hash.consensus_encode(s)
|
||||||
}
|
}
|
||||||
|
@ -115,9 +115,9 @@ impl<D:SimpleDecoder<E>, E> ConsensusDecodable<D, E> for Inventory {
|
||||||
let int_type: u32 = try!(ConsensusDecodable::consensus_decode(d));
|
let int_type: u32 = try!(ConsensusDecodable::consensus_decode(d));
|
||||||
Ok(Inventory {
|
Ok(Inventory {
|
||||||
inv_type: match int_type {
|
inv_type: match int_type {
|
||||||
0 => InvError,
|
0 => InvType::Error,
|
||||||
1 => InvTransaction,
|
1 => InvType::Transaction,
|
||||||
2 => InvBlock,
|
2 => InvType::Block,
|
||||||
// TODO do not fail here
|
// TODO do not fail here
|
||||||
_ => { panic!("bad inventory type field") }
|
_ => { panic!("bad inventory type field") }
|
||||||
},
|
},
|
||||||
|
|
|
@ -47,15 +47,6 @@ impl ::std::fmt::Debug for Sha256dHash {
|
||||||
pub struct Ripemd160Hash([u8; 20]);
|
pub struct Ripemd160Hash([u8; 20]);
|
||||||
impl_array_newtype!(Ripemd160Hash, u8, 20);
|
impl_array_newtype!(Ripemd160Hash, u8, 20);
|
||||||
|
|
||||||
/// A "hasher" which just truncates and adds data to its state. Should
|
|
||||||
/// only be used for hashtables indexed by "already random" data such
|
|
||||||
/// as SHA2 hashes
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
||||||
pub struct DumbHasher;
|
|
||||||
|
|
||||||
/// The state of a `DumbHasher`
|
|
||||||
pub struct DumbHasherState([u8; 8]);
|
|
||||||
|
|
||||||
/// A 32-bit hash obtained by truncating a real hash
|
/// A 32-bit hash obtained by truncating a real hash
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub struct Hash32((u8, u8, u8, u8));
|
pub struct Hash32((u8, u8, u8, u8));
|
||||||
|
@ -68,44 +59,6 @@ pub struct Hash48((u8, u8, u8, u8, u8, u8));
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub struct Hash64((u8, u8, u8, u8, u8, u8, u8, u8));
|
pub struct Hash64((u8, u8, u8, u8, u8, u8, u8, u8));
|
||||||
|
|
||||||
|
|
||||||
// Allow these to be used as a key for Rust's HashMap et. al.
|
|
||||||
impl hash::Hash<DumbHasherState> for Sha256dHash {
|
|
||||||
#[inline]
|
|
||||||
fn hash(&self, state: &mut DumbHasherState) {
|
|
||||||
let &Sha256dHash(ref hash) = self;
|
|
||||||
let &DumbHasherState(ref mut arr) = state;
|
|
||||||
for i in 0..8 {
|
|
||||||
arr[i] += hash[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl hash::Hasher<DumbHasherState> for DumbHasher {
|
|
||||||
#[inline]
|
|
||||||
fn hash<T: hash::Hash<DumbHasherState>>(&self, value: &T) -> u64 {
|
|
||||||
let mut ret = DumbHasherState([0; 8]);
|
|
||||||
value.hash(&mut ret);
|
|
||||||
let DumbHasherState(res) = ret;
|
|
||||||
LittleEndian::read_u64(&res[0..8])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl hash::Writer for DumbHasherState {
|
|
||||||
#[inline]
|
|
||||||
fn write(&mut self, msg: &[u8]) {
|
|
||||||
let &DumbHasherState(ref mut arr) = self;
|
|
||||||
for (n, &ch) in msg.iter().enumerate() {
|
|
||||||
arr[n % 8] += ch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for DumbHasher {
|
|
||||||
#[inline]
|
|
||||||
fn default() -> DumbHasher { DumbHasher }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ripemd160Hash {
|
impl Ripemd160Hash {
|
||||||
/// Create a hash by hashing some data
|
/// Create a hash by hashing some data
|
||||||
pub fn from_data(data: &[u8]) -> Ripemd160Hash {
|
pub fn from_data(data: &[u8]) -> Ripemd160Hash {
|
||||||
|
|
|
@ -238,8 +238,8 @@ impl<K:BitArray+cmp::Eq+Zero+One+ops::BitXor<K,K>+ops::Shl<usize,K>+ops::Shr<usi
|
||||||
}
|
}
|
||||||
match (tree.child_l.take(), tree.child_r.take()) {
|
match (tree.child_l.take(), tree.child_r.take()) {
|
||||||
(Some(_), Some(_)) => unreachable!(),
|
(Some(_), Some(_)) => unreachable!(),
|
||||||
(Some(Box::new(PatriciaTree { data, child_l, child_r, skip_prefix, skip_len })), None) |
|
(Some(box PatriciaTree { data, child_l, child_r, skip_prefix, skip_len }), None) |
|
||||||
(None, Some(Box::new(PatriciaTree { data, child_l, child_r, skip_prefix, skip_len }))) => {
|
(None, Some(box PatriciaTree { data, child_l, child_r, skip_prefix, skip_len })) => {
|
||||||
tree.data = data;
|
tree.data = data;
|
||||||
tree.child_l = child_l;
|
tree.child_l = child_l;
|
||||||
tree.child_r = child_r;
|
tree.child_r = child_r;
|
||||||
|
@ -296,8 +296,8 @@ impl<K:BitArray+cmp::Eq+Zero+One+ops::BitXor<K,K>+ops::Shl<usize,K>+ops::Shr<usi
|
||||||
return (false, ret);
|
return (false, ret);
|
||||||
}
|
}
|
||||||
// One child? Consolidate
|
// One child? Consolidate
|
||||||
(bit, Some(Box::new(PatriciaTree { data, child_l, child_r, skip_prefix, skip_len })), None) |
|
(bit, Some(box PatriciaTree { data, child_l, child_r, skip_prefix, skip_len }), None) |
|
||||||
(bit, None, Some(Box::new(PatriciaTree { data, child_l, child_r, skip_prefix, skip_len }))) => {
|
(bit, None, Some(box PatriciaTree { data, child_l, child_r, skip_prefix, skip_len })) => {
|
||||||
tree.data = data;
|
tree.data = data;
|
||||||
tree.child_l = child_l;
|
tree.child_l = child_l;
|
||||||
tree.child_r = child_r;
|
tree.child_r = child_r;
|
||||||
|
|
|
@ -22,7 +22,7 @@ use crypto::sha2::Sha256;
|
||||||
|
|
||||||
use blockdata::script::Script;
|
use blockdata::script::Script;
|
||||||
use blockdata::opcodes;
|
use blockdata::opcodes;
|
||||||
use network::constants::Network::{self, Bitcoin, BitcoinTestnet};
|
use network::constants::Network;
|
||||||
use util::hash::Ripemd160Hash;
|
use util::hash::Ripemd160Hash;
|
||||||
use util::base58::{self, FromBase58, ToBase58};
|
use util::base58::{self, FromBase58, ToBase58};
|
||||||
|
|
||||||
|
@ -89,8 +89,8 @@ impl ToBase58 for Address {
|
||||||
fn base58_layout(&self) -> Vec<u8> {
|
fn base58_layout(&self) -> Vec<u8> {
|
||||||
let mut ret = vec![
|
let mut ret = vec![
|
||||||
match self.network {
|
match self.network {
|
||||||
Bitcoin => 0,
|
Network::Bitcoin => 0,
|
||||||
BitcoinTestnet => 111
|
Network::Testnet => 111
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
ret.push_all(self.hash.as_slice());
|
ret.push_all(self.hash.as_slice());
|
||||||
|
@ -106,8 +106,8 @@ impl FromBase58 for Address {
|
||||||
|
|
||||||
Ok(Address {
|
Ok(Address {
|
||||||
network: match data[0] {
|
network: match data[0] {
|
||||||
0 => Bitcoin,
|
0 => Network::Bitcoin,
|
||||||
111 => BitcoinTestnet,
|
111 => Network::Testnet,
|
||||||
x => { return Err(base58::Error::InvalidVersion(vec![x])); }
|
x => { return Err(base58::Error::InvalidVersion(vec![x])); }
|
||||||
},
|
},
|
||||||
hash: Ripemd160Hash::from_slice(data.slice_from(1))
|
hash: Ripemd160Hash::from_slice(data.slice_from(1))
|
||||||
|
|
|
@ -30,7 +30,7 @@ use blockdata::script::Script;
|
||||||
use network::constants::Network;
|
use network::constants::Network;
|
||||||
use wallet::address::Address;
|
use wallet::address::Address;
|
||||||
use wallet::wallet::Wallet;
|
use wallet::wallet::Wallet;
|
||||||
use util::hash::{DumbHasher, Sha256dHash};
|
use util::hash::Sha256dHash;
|
||||||
|
|
||||||
/// The type of a wallet-spendable txout
|
/// The type of a wallet-spendable txout
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
|
@ -61,7 +61,7 @@ pub struct WalletTxOut {
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub struct AddressIndex {
|
pub struct AddressIndex {
|
||||||
tentative_index: HashMap<Script, Vec<WalletTxOut>>,
|
tentative_index: HashMap<Script, Vec<WalletTxOut>>,
|
||||||
index: HashMap<(Sha256dHash, u32), Vec<WalletTxOut>, DumbHasher>,
|
index: HashMap<(Sha256dHash, u32), Vec<WalletTxOut>, SipHasher>,
|
||||||
network: Network,
|
network: Network,
|
||||||
k1: u64,
|
k1: u64,
|
||||||
k2: u64
|
k2: u64
|
||||||
|
@ -74,7 +74,7 @@ impl AddressIndex {
|
||||||
let (k1, k2) = wallet.siphash_key();
|
let (k1, k2) = wallet.siphash_key();
|
||||||
let mut ret = AddressIndex {
|
let mut ret = AddressIndex {
|
||||||
tentative_index: HashMap::with_capacity(utxo_set.n_utxos() / 256),
|
tentative_index: HashMap::with_capacity(utxo_set.n_utxos() / 256),
|
||||||
index: HashMap::with_hasher(DumbHasher),
|
index: HashMap::with_hasher(SipHasher::new()),
|
||||||
network: wallet.network(),
|
network: wallet.network(),
|
||||||
k1: k1,
|
k1: k1,
|
||||||
k2: k2
|
k2: k2
|
||||||
|
|
|
@ -29,7 +29,7 @@ use crypto::sha2::Sha512;
|
||||||
use secp256k1::key::{PublicKey, SecretKey};
|
use secp256k1::key::{PublicKey, SecretKey};
|
||||||
use secp256k1;
|
use secp256k1;
|
||||||
|
|
||||||
use network::constants::Network::{self, Bitcoin, BitcoinTestnet};
|
use network::constants::Network;
|
||||||
use util::base58;
|
use util::base58;
|
||||||
use util::base58::{FromBase58, ToBase58};
|
use util::base58::{FromBase58, ToBase58};
|
||||||
|
|
||||||
|
@ -288,8 +288,8 @@ impl ToBase58 for ExtendedPrivKey {
|
||||||
fn base58_layout(&self) -> Vec<u8> {
|
fn base58_layout(&self) -> Vec<u8> {
|
||||||
let mut ret = Vec::with_capacity(78);
|
let mut ret = Vec::with_capacity(78);
|
||||||
ret.push_all(match self.network {
|
ret.push_all(match self.network {
|
||||||
Bitcoin => [0x04, 0x88, 0xAD, 0xE4],
|
Network::Bitcoin => [0x04, 0x88, 0xAD, 0xE4],
|
||||||
BitcoinTestnet => [0x04, 0x35, 0x83, 0x94]
|
Network::Testnet => [0x04, 0x35, 0x83, 0x94]
|
||||||
});
|
});
|
||||||
ret.push(self.depth as u8);
|
ret.push(self.depth as u8);
|
||||||
ret.push_all(self.parent_fingerprint.as_slice());
|
ret.push_all(self.parent_fingerprint.as_slice());
|
||||||
|
@ -320,8 +320,8 @@ impl FromBase58 for ExtendedPrivKey {
|
||||||
|
|
||||||
Ok(ExtendedPrivKey {
|
Ok(ExtendedPrivKey {
|
||||||
network: match data.slice_to(4) {
|
network: match data.slice_to(4) {
|
||||||
[0x04, 0x88, 0xAD, 0xE4] => Bitcoin,
|
[0x04, 0x88, 0xAD, 0xE4] => Network::Bitcoin,
|
||||||
[0x04, 0x35, 0x83, 0x94] => BitcoinTestnet,
|
[0x04, 0x35, 0x83, 0x94] => Network::Testnet,
|
||||||
_ => { return Err(base58::Error::InvalidVersion(data.slice_to(4).to_vec())); }
|
_ => { return Err(base58::Error::InvalidVersion(data.slice_to(4).to_vec())); }
|
||||||
},
|
},
|
||||||
depth: data[4],
|
depth: data[4],
|
||||||
|
@ -340,8 +340,8 @@ impl ToBase58 for ExtendedPubKey {
|
||||||
assert!(self.public_key.is_compressed());
|
assert!(self.public_key.is_compressed());
|
||||||
let mut ret = Vec::with_capacity(78);
|
let mut ret = Vec::with_capacity(78);
|
||||||
ret.push_all(match self.network {
|
ret.push_all(match self.network {
|
||||||
Bitcoin => [0x04, 0x88, 0xB2, 0x1E],
|
Network::Bitcoin => [0x04, 0x88, 0xB2, 0x1E],
|
||||||
BitcoinTestnet => [0x04, 0x35, 0x87, 0xCF]
|
Network::Testnet => [0x04, 0x35, 0x87, 0xCF]
|
||||||
});
|
});
|
||||||
ret.push(self.depth as u8);
|
ret.push(self.depth as u8);
|
||||||
ret.push_all(self.parent_fingerprint.as_slice());
|
ret.push_all(self.parent_fingerprint.as_slice());
|
||||||
|
@ -371,8 +371,8 @@ impl FromBase58 for ExtendedPubKey {
|
||||||
|
|
||||||
Ok(ExtendedPubKey {
|
Ok(ExtendedPubKey {
|
||||||
network: match data.slice_to(4) {
|
network: match data.slice_to(4) {
|
||||||
[0x04, 0x88, 0xB2, 0x1E] => Bitcoin,
|
[0x04, 0x88, 0xB2, 0x1E] => Network::Bitcoin,
|
||||||
[0x04, 0x35, 0x87, 0xCF] => BitcoinTestnet,
|
[0x04, 0x35, 0x87, 0xCF] => Network::Testnet,
|
||||||
_ => { return Err(base58::Error::InvalidVersion(data.slice_to(4).to_vec())); }
|
_ => { return Err(base58::Error::InvalidVersion(data.slice_to(4).to_vec())); }
|
||||||
},
|
},
|
||||||
depth: data[4],
|
depth: data[4],
|
||||||
|
|
Loading…
Reference in New Issue