Add alternate network support to `Blockchain`, `UtxoSet`, `Socket`
Still need to do alternate diffchange rules..
This commit is contained in:
parent
8f826a959d
commit
51038f5810
|
@ -30,7 +30,8 @@ use std::kinds::marker;
|
||||||
|
|
||||||
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, max_target};
|
use blockdata::constants::{DIFFCHANGE_INTERVAL, DIFFCHANGE_TIMESPAN, max_target, genesis_block};
|
||||||
|
use network::constants::Network;
|
||||||
use network::serialize::{Serializable, SerializeIter};
|
use network::serialize::{Serializable, SerializeIter};
|
||||||
use util::BitArray;
|
use util::BitArray;
|
||||||
use util::error::{BitcoinResult, BlockNotFound, DuplicateHash, PrevHashNotFound};
|
use util::error::{BitcoinResult, BlockNotFound, DuplicateHash, PrevHashNotFound};
|
||||||
|
@ -134,6 +135,7 @@ impl Serializable for Rc<BlockchainNode> {
|
||||||
|
|
||||||
/// The blockchain
|
/// The blockchain
|
||||||
pub struct Blockchain {
|
pub struct Blockchain {
|
||||||
|
network: Network,
|
||||||
tree: BlockTree,
|
tree: BlockTree,
|
||||||
best_tip: Rc<BlockchainNode>,
|
best_tip: Rc<BlockchainNode>,
|
||||||
best_hash: Sha256dHash,
|
best_hash: Sha256dHash,
|
||||||
|
@ -143,6 +145,7 @@ pub struct Blockchain {
|
||||||
impl Serializable for Blockchain {
|
impl Serializable for Blockchain {
|
||||||
fn serialize(&self) -> Vec<u8> {
|
fn serialize(&self) -> Vec<u8> {
|
||||||
let mut ret = vec![];
|
let mut ret = vec![];
|
||||||
|
ret.extend(self.network.serialize().move_iter());
|
||||||
ret.extend(self.tree.serialize().move_iter());
|
ret.extend(self.tree.serialize().move_iter());
|
||||||
ret.extend(self.best_hash.serialize().move_iter());
|
ret.extend(self.best_hash.serialize().move_iter());
|
||||||
ret.extend(self.genesis_hash.serialize().move_iter());
|
ret.extend(self.genesis_hash.serialize().move_iter());
|
||||||
|
@ -152,7 +155,8 @@ impl Serializable for Blockchain {
|
||||||
fn serialize_iter<'a>(&'a self) -> SerializeIter<'a> {
|
fn serialize_iter<'a>(&'a self) -> SerializeIter<'a> {
|
||||||
SerializeIter {
|
SerializeIter {
|
||||||
data_iter: None,
|
data_iter: None,
|
||||||
sub_iter_iter: box vec![ &self.tree as &Serializable,
|
sub_iter_iter: box vec![ &self.network as &Serializable,
|
||||||
|
&self.tree as &Serializable,
|
||||||
&self.best_hash as &Serializable,
|
&self.best_hash as &Serializable,
|
||||||
&self.genesis_hash as &Serializable ].move_iter(),
|
&self.genesis_hash as &Serializable ].move_iter(),
|
||||||
sub_iter: None,
|
sub_iter: None,
|
||||||
|
@ -161,6 +165,7 @@ impl Serializable for Blockchain {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize<I: Iterator<u8>>(mut iter: I) -> IoResult<Blockchain> {
|
fn deserialize<I: Iterator<u8>>(mut iter: I) -> IoResult<Blockchain> {
|
||||||
|
let network: Network = try!(prepend_err("network", Serializable::deserialize(iter.by_ref())));
|
||||||
let tree: BlockTree = try!(prepend_err("tree", Serializable::deserialize(iter.by_ref())));
|
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 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())));
|
let genesis_hash: Sha256dHash = try!(prepend_err("genesis_hash", Serializable::deserialize(iter.by_ref())));
|
||||||
|
@ -201,6 +206,7 @@ impl Serializable for Blockchain {
|
||||||
} else {
|
} else {
|
||||||
// Return the chain
|
// Return the chain
|
||||||
Ok(Blockchain {
|
Ok(Blockchain {
|
||||||
|
network: network,
|
||||||
tree: tree,
|
tree: tree,
|
||||||
best_tip: best.clone(),
|
best_tip: best.clone(),
|
||||||
best_hash: best_hash,
|
best_hash: best_hash,
|
||||||
|
@ -367,7 +373,8 @@ fn satoshi_the_precision(n: &Uint256) -> Uint256 {
|
||||||
|
|
||||||
impl Blockchain {
|
impl Blockchain {
|
||||||
/// Constructs a new blockchain
|
/// Constructs a new blockchain
|
||||||
pub fn new(genesis: Block) -> Blockchain {
|
pub fn new(network: Network) -> Blockchain {
|
||||||
|
let genesis = genesis_block(network);
|
||||||
let genhash = genesis.header.hash();
|
let genhash = genesis.header.hash();
|
||||||
let rc_gen = Rc::new(BlockchainNode {
|
let rc_gen = Rc::new(BlockchainNode {
|
||||||
total_work: Zero::zero(),
|
total_work: Zero::zero(),
|
||||||
|
@ -379,6 +386,7 @@ impl Blockchain {
|
||||||
next: RefCell::new(None)
|
next: RefCell::new(None)
|
||||||
});
|
});
|
||||||
Blockchain {
|
Blockchain {
|
||||||
|
network: network,
|
||||||
tree: {
|
tree: {
|
||||||
let mut pat = PatriciaTree::new();
|
let mut pat = PatriciaTree::new();
|
||||||
pat.insert(&genhash.as_uint256(), 256, rc_gen.clone());
|
pat.insert(&genhash.as_uint256(), 256, rc_gen.clone());
|
||||||
|
@ -479,7 +487,7 @@ impl Blockchain {
|
||||||
target = target.mul_u32(timespan);
|
target = target.mul_u32(timespan);
|
||||||
target = target / FromPrimitive::from_u64(DIFFCHANGE_TIMESPAN as u64).unwrap();
|
target = target / FromPrimitive::from_u64(DIFFCHANGE_TIMESPAN as u64).unwrap();
|
||||||
// Clamp below MAX_TARGET (difficulty 1)
|
// Clamp below MAX_TARGET (difficulty 1)
|
||||||
let max = max_target();
|
let max = max_target(self.network);
|
||||||
if target > max { target = max };
|
if target > max { target = max };
|
||||||
// Compactify (make expressible in the 8+24 nBits float format
|
// Compactify (make expressible in the 8+24 nBits float format
|
||||||
satoshi_the_precision(&target)
|
satoshi_the_precision(&target)
|
||||||
|
@ -601,12 +609,14 @@ mod tests {
|
||||||
|
|
||||||
use blockdata::blockchain::Blockchain;
|
use blockdata::blockchain::Blockchain;
|
||||||
use blockdata::constants::genesis_block;
|
use blockdata::constants::genesis_block;
|
||||||
|
use network::constants::Bitcoin;
|
||||||
use network::serialize::Serializable;
|
use network::serialize::Serializable;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn blockchain_serialize_test() {
|
fn blockchain_serialize_test() {
|
||||||
let empty_chain = Blockchain::new(genesis_block());
|
let empty_chain = Blockchain::new(Bitcoin);
|
||||||
assert_eq!(empty_chain.best_tip.hash().serialize(), genesis_block().header.hash().serialize());
|
assert_eq!(empty_chain.best_tip.hash().serialize(),
|
||||||
|
genesis_block(Bitcoin).header.hash().serialize());
|
||||||
|
|
||||||
let serial = empty_chain.serialize();
|
let serial = empty_chain.serialize();
|
||||||
assert_eq!(serial, empty_chain.serialize_iter().collect());
|
assert_eq!(serial, empty_chain.serialize_iter().collect());
|
||||||
|
@ -614,7 +624,8 @@ mod tests {
|
||||||
let deserial: IoResult<Blockchain> = Serializable::deserialize(serial.iter().map(|n| *n));
|
let deserial: IoResult<Blockchain> = Serializable::deserialize(serial.iter().map(|n| *n));
|
||||||
assert!(deserial.is_ok());
|
assert!(deserial.is_ok());
|
||||||
let read_chain = deserial.unwrap();
|
let read_chain = deserial.unwrap();
|
||||||
assert_eq!(read_chain.best_tip.hash().serialize(), genesis_block().header.hash().serialize());
|
assert_eq!(read_chain.best_tip.hash().serialize(),
|
||||||
|
genesis_block(Bitcoin).header.hash().serialize());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
//! single transaction
|
//! single transaction
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
use network::constants::{Network, Bitcoin, BitcoinTestnet};
|
||||||
|
|
||||||
use std::num::from_u64;
|
use std::num::from_u64;
|
||||||
|
|
||||||
use blockdata::opcodes;
|
use blockdata::opcodes;
|
||||||
|
@ -35,12 +37,12 @@ pub static DIFFCHANGE_INTERVAL: u32 = 2016;
|
||||||
pub static DIFFCHANGE_TIMESPAN: u32 = 14 * 24 * 3600;
|
pub static DIFFCHANGE_TIMESPAN: u32 = 14 * 24 * 3600;
|
||||||
|
|
||||||
/// In Bitcoind this is insanely described as ~((u256)0 >> 32)
|
/// In Bitcoind this is insanely described as ~((u256)0 >> 32)
|
||||||
pub fn max_target() -> Uint256 {
|
pub fn max_target(_: Network) -> Uint256 {
|
||||||
from_u64::<Uint256>(0xFFFF).unwrap() << 208u
|
from_u64::<Uint256>(0xFFFF).unwrap() << 208u
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs and returns the coinbase (and only) transaction of the genesis block
|
/// Constructs and returns the coinbase (and only) transaction of the Bitcoin genesis block
|
||||||
pub fn genesis_tx() -> Transaction {
|
fn bitcoin_genesis_tx() -> Transaction {
|
||||||
// Base
|
// Base
|
||||||
let mut ret = Transaction {
|
let mut ret = Transaction {
|
||||||
version: 1,
|
version: 1,
|
||||||
|
@ -75,34 +77,51 @@ pub fn genesis_tx() -> Transaction {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs and returns the genesis block
|
/// Constructs and returns the genesis block
|
||||||
pub fn genesis_block() -> Block {
|
pub fn genesis_block(network: Network) -> Block {
|
||||||
let txdata = vec![genesis_tx()];
|
match network {
|
||||||
let header = BlockHeader {
|
Bitcoin => {
|
||||||
version: 1,
|
let txdata = vec![bitcoin_genesis_tx()];
|
||||||
prev_blockhash: zero_hash(),
|
Block {
|
||||||
merkle_root: merkle_root(txdata.as_slice()),
|
header: BlockHeader {
|
||||||
time: 1231006505,
|
version: 1,
|
||||||
bits: 0x1d00ffff,
|
prev_blockhash: zero_hash(),
|
||||||
nonce: 2083236893
|
merkle_root: merkle_root(txdata.as_slice()),
|
||||||
};
|
time: 1231006505,
|
||||||
|
bits: 0x1d00ffff,
|
||||||
Block {
|
nonce: 2083236893
|
||||||
header: header,
|
},
|
||||||
txdata: txdata
|
txdata: txdata
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BitcoinTestnet => {
|
||||||
|
let txdata = vec![bitcoin_genesis_tx()];
|
||||||
|
Block {
|
||||||
|
header: BlockHeader {
|
||||||
|
version: 1,
|
||||||
|
prev_blockhash: zero_hash(),
|
||||||
|
merkle_root: merkle_root(txdata.as_slice()),
|
||||||
|
time: 1296688602,
|
||||||
|
bits: 0x1d00ffff,
|
||||||
|
nonce: 414098458
|
||||||
|
},
|
||||||
|
txdata: txdata
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use network::serialize::Serializable;
|
use network::serialize::Serializable;
|
||||||
use blockdata::constants::{genesis_block, genesis_tx};
|
use network::constants::{Bitcoin, BitcoinTestnet};
|
||||||
|
use blockdata::constants::{genesis_block, bitcoin_genesis_tx};
|
||||||
use blockdata::constants::{MAX_SEQUENCE, COIN_VALUE};
|
use blockdata::constants::{MAX_SEQUENCE, COIN_VALUE};
|
||||||
use util::misc::hex_bytes;
|
use util::misc::hex_bytes;
|
||||||
use util::hash::zero_hash;
|
use util::hash::zero_hash;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn genesis_first_transaction() {
|
fn bitcoin_genesis_first_transaction() {
|
||||||
let gen = genesis_tx();
|
let gen = bitcoin_genesis_tx();
|
||||||
|
|
||||||
assert_eq!(gen.version, 1);
|
assert_eq!(gen.version, 1);
|
||||||
assert_eq!(gen.input.len(), 1);
|
assert_eq!(gen.input.len(), 1);
|
||||||
|
@ -123,18 +142,32 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn genesis_full_block() {
|
fn bitcoin_genesis_full_block() {
|
||||||
let gen = genesis_block();
|
let gen = genesis_block(Bitcoin);
|
||||||
|
|
||||||
assert_eq!(gen.header.version, 1);
|
assert_eq!(gen.header.version, 1);
|
||||||
assert_eq!(gen.header.prev_blockhash.as_slice(), zero_hash().as_slice());
|
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>>(),
|
assert_eq!(gen.header.merkle_root.le_hex_string(),
|
||||||
hex_bytes("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b").unwrap());
|
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".to_string());
|
||||||
assert_eq!(gen.header.time, 1231006505);
|
assert_eq!(gen.header.time, 1231006505);
|
||||||
assert_eq!(gen.header.bits, 0x1d00ffff);
|
assert_eq!(gen.header.bits, 0x1d00ffff);
|
||||||
assert_eq!(gen.header.nonce, 2083236893);
|
assert_eq!(gen.header.nonce, 2083236893);
|
||||||
assert_eq!(gen.header.hash().serialize().iter().rev().map(|n| *n).collect::<Vec<u8>>(),
|
assert_eq!(gen.header.hash().le_hex_string(),
|
||||||
hex_bytes("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f").unwrap());
|
"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn testnet_genesis_full_block() {
|
||||||
|
let gen = genesis_block(BitcoinTestnet);
|
||||||
|
assert_eq!(gen.header.version, 1);
|
||||||
|
assert_eq!(gen.header.prev_blockhash.as_slice(), zero_hash().as_slice());
|
||||||
|
assert_eq!(gen.header.merkle_root.le_hex_string(),
|
||||||
|
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".to_string());
|
||||||
|
assert_eq!(gen.header.time, 1296688602);
|
||||||
|
assert_eq!(gen.header.bits, 0x1d00ffff);
|
||||||
|
assert_eq!(gen.header.nonce, 414098458);
|
||||||
|
assert_eq!(gen.header.hash().le_hex_string(),
|
||||||
|
"000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943".to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,9 @@ use std::io::IoResult;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use blockdata::transaction::{Transaction, TxOut};
|
use blockdata::transaction::{Transaction, TxOut};
|
||||||
|
use blockdata::constants::genesis_block;
|
||||||
use blockdata::block::Block;
|
use blockdata::block::Block;
|
||||||
|
use network::constants::Network;
|
||||||
use network::serialize::{Serializable, SerializeIter};
|
use network::serialize::{Serializable, SerializeIter};
|
||||||
use util::hash::Sha256dHash;
|
use util::hash::Sha256dHash;
|
||||||
use util::uint::Uint128;
|
use util::uint::Uint128;
|
||||||
|
@ -51,14 +53,14 @@ impl_serializable!(UtxoSet, last_hash, n_utxos, spent_txos, spent_idx, tree)
|
||||||
|
|
||||||
impl UtxoSet {
|
impl UtxoSet {
|
||||||
/// Constructs a new UTXO set
|
/// Constructs a new UTXO set
|
||||||
pub fn new(genesis: Block, rewind_limit: uint) -> UtxoSet {
|
pub fn new(network: Network, rewind_limit: uint) -> UtxoSet {
|
||||||
// There is in fact a transaction in the genesis block, but the Bitcoin
|
// 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
|
// reference client does not add its sole output to the UTXO set. We
|
||||||
// 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 {
|
||||||
tree: PatriciaTree::new(),
|
tree: PatriciaTree::new(),
|
||||||
last_hash: genesis.header.hash(),
|
last_hash: genesis_block(network).header.hash(),
|
||||||
spent_txos: Vec::from_elem(rewind_limit, vec![]),
|
spent_txos: Vec::from_elem(rewind_limit, vec![]),
|
||||||
spent_idx: 0,
|
spent_idx: 0,
|
||||||
n_utxos: 0
|
n_utxos: 0
|
||||||
|
@ -270,14 +272,14 @@ mod tests {
|
||||||
use std::io::IoResult;
|
use std::io::IoResult;
|
||||||
use serialize::hex::FromHex;
|
use serialize::hex::FromHex;
|
||||||
|
|
||||||
use blockdata::constants::genesis_block;
|
|
||||||
use blockdata::block::Block;
|
use blockdata::block::Block;
|
||||||
use blockdata::utxoset::UtxoSet;
|
use blockdata::utxoset::UtxoSet;
|
||||||
|
use network::constants::Bitcoin;
|
||||||
use network::serialize::Serializable;
|
use network::serialize::Serializable;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn utxoset_serialize_test() {
|
fn utxoset_serialize_test() {
|
||||||
let mut empty_set = UtxoSet::new(genesis_block(), 100);
|
let mut empty_set = UtxoSet::new(Bitcoin, 100);
|
||||||
|
|
||||||
let new_block: Block = Serializable::deserialize("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b0201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d026e04ffffffff0100f2052a0100000043410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac00000000010000000321f75f3139a013f50f315b23b0c9a2b6eac31e2bec98e5891c924664889942260000000049483045022100cb2c6b346a978ab8c61b18b5e9397755cbd17d6eb2fe0083ef32e067fa6c785a02206ce44e613f31d9a6b0517e46f3db1576e9812cc98d159bfdaf759a5014081b5c01ffffffff79cda0945903627c3da1f85fc95d0b8ee3e76ae0cfdc9a65d09744b1f8fc85430000000049483045022047957cdd957cfd0becd642f6b84d82f49b6cb4c51a91f49246908af7c3cfdf4a022100e96b46621f1bffcf5ea5982f88cef651e9354f5791602369bf5a82a6cd61a62501fffffffffe09f5fe3ffbf5ee97a54eb5e5069e9da6b4856ee86fc52938c2f979b0f38e82000000004847304402204165be9a4cbab8049e1af9723b96199bfd3e85f44c6b4c0177e3962686b26073022028f638da23fc003760861ad481ead4099312c60030d4cb57820ce4d33812a5ce01ffffffff01009d966b01000000434104ea1feff861b51fe3f5f8a3b12d0f4712db80e919548a80839fc47c6a21e66d957e9c5d8cd108c7a2d2324bad71f9904ac0ae7336507d785b17a2c115e427a32fac00000000".from_hex().unwrap().iter().map(|n| *n)).unwrap();
|
let new_block: Block = Serializable::deserialize("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b0201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d026e04ffffffff0100f2052a0100000043410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac00000000010000000321f75f3139a013f50f315b23b0c9a2b6eac31e2bec98e5891c924664889942260000000049483045022100cb2c6b346a978ab8c61b18b5e9397755cbd17d6eb2fe0083ef32e067fa6c785a02206ce44e613f31d9a6b0517e46f3db1576e9812cc98d159bfdaf759a5014081b5c01ffffffff79cda0945903627c3da1f85fc95d0b8ee3e76ae0cfdc9a65d09744b1f8fc85430000000049483045022047957cdd957cfd0becd642f6b84d82f49b6cb4c51a91f49246908af7c3cfdf4a022100e96b46621f1bffcf5ea5982f88cef651e9354f5791602369bf5a82a6cd61a62501fffffffffe09f5fe3ffbf5ee97a54eb5e5069e9da6b4856ee86fc52938c2f979b0f38e82000000004847304402204165be9a4cbab8049e1af9723b96199bfd3e85f44c6b4c0177e3962686b26073022028f638da23fc003760861ad481ead4099312c60030d4cb57820ce4d33812a5ce01ffffffff01009d966b01000000434104ea1feff861b51fe3f5f8a3b12d0f4712db80e919548a80839fc47c6a21e66d957e9c5d8cd108c7a2d2324bad71f9904ac0ae7336507d785b17a2c115e427a32fac00000000".from_hex().unwrap().iter().map(|n| *n)).unwrap();
|
||||||
|
|
||||||
|
|
|
@ -62,4 +62,3 @@ pub mod network;
|
||||||
pub mod blockdata;
|
pub mod blockdata;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,10 +18,47 @@
|
||||||
//! protocol, such as protocol versioning and magic header bytes.
|
//! protocol, such as protocol versioning and magic header bytes.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
pub static MAGIC_BITCOIN: u32 = 0xD9B4BEF9;
|
use std::io::{IoResult, InvalidInput, standard_error};
|
||||||
pub static MAGIC_TESTNET: u32 = 0x0709110B;
|
|
||||||
|
use network::serialize::Serializable;
|
||||||
|
use util::misc::prepend_err;
|
||||||
|
|
||||||
|
/// The cryptocurrency to operate on
|
||||||
|
#[deriving(PartialEq, Eq, Clone, Show)]
|
||||||
|
pub enum Network {
|
||||||
|
/// Classic Bitcoin
|
||||||
|
Bitcoin,
|
||||||
|
/// Bitcoin's testnet
|
||||||
|
BitcoinTestnet,
|
||||||
|
}
|
||||||
|
|
||||||
pub static PROTOCOL_VERSION: u32 = 70001;
|
pub static PROTOCOL_VERSION: u32 = 70001;
|
||||||
pub static SERVICES: u64 = 0;
|
pub static SERVICES: u64 = 0;
|
||||||
pub static USER_AGENT: &'static str = "bitcoin-rust v0.1";
|
pub static USER_AGENT: &'static str = "bitcoin-rust v0.1";
|
||||||
|
|
||||||
|
/// Return the network magic bytes, which should be encoded little-endian
|
||||||
|
/// at the start of every message
|
||||||
|
pub fn magic(network: Network) -> u32 {
|
||||||
|
match network {
|
||||||
|
Bitcoin => 0xD9B4BEF9,
|
||||||
|
BitcoinTestnet => 0x0709110B
|
||||||
|
// Note: any new entries here must be added to `deserialize` below
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This affects the representation of the `Network` in text files
|
||||||
|
impl Serializable for Network {
|
||||||
|
fn serialize(&self) -> Vec<u8> {
|
||||||
|
magic(*self).serialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize<I: Iterator<u8>>(iter: I) -> IoResult<Network> {
|
||||||
|
let magic: u32 = try!(prepend_err("magic", Serializable::deserialize(iter)));
|
||||||
|
match magic {
|
||||||
|
0xD9B4BEF9 => Ok(Bitcoin),
|
||||||
|
0x0709110B => Ok(BitcoinTestnet),
|
||||||
|
_ => Err(standard_error(InvalidInput))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
use std::io::{IoResult, standard_error, ConnectionFailed};
|
use std::io::{IoResult, standard_error, ConnectionFailed};
|
||||||
use std::io::timer;
|
use std::io::timer;
|
||||||
|
|
||||||
|
use network::constants::Network;
|
||||||
use network::message::{NetworkMessage, Verack};
|
use network::message::{NetworkMessage, Verack};
|
||||||
use network::socket::Socket;
|
use network::socket::Socket;
|
||||||
|
|
||||||
|
@ -30,12 +31,12 @@ pub trait Listener {
|
||||||
fn peer<'a>(&'a self) -> &'a str;
|
fn peer<'a>(&'a self) -> &'a str;
|
||||||
/// Return the port we have connected to the peer on
|
/// Return the port we have connected to the peer on
|
||||||
fn port(&self) -> u16;
|
fn port(&self) -> u16;
|
||||||
/// Return the network magic
|
/// Return the network this `Listener` is operating on
|
||||||
fn magic(&self) -> u32;
|
fn network(&self) -> Network;
|
||||||
/// Main listen loop
|
/// Main listen loop
|
||||||
fn start(&self) -> IoResult<(Receiver<NetworkMessage>, Socket)> {
|
fn start(&self) -> IoResult<(Receiver<NetworkMessage>, Socket)> {
|
||||||
// Open socket
|
// Open socket
|
||||||
let mut ret_sock = Socket::new(self.magic());
|
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(standard_error(ConnectionFailed))
|
Err(_) => return Err(standard_error(ConnectionFailed))
|
||||||
|
|
|
@ -76,9 +76,6 @@ impl<'a> Iterator<u8> for SerializeIter<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A string which must be encoded as 12 bytes, used in network message headers
|
|
||||||
|
|
||||||
|
|
||||||
#[deriving(PartialEq, Clone, Show)]
|
#[deriving(PartialEq, Clone, Show)]
|
||||||
/// Data which must be preceded by a 4-byte checksum
|
/// Data which must be preceded by a 4-byte checksum
|
||||||
pub struct CheckedData(pub Vec<u8>);
|
pub struct CheckedData(pub Vec<u8>);
|
||||||
|
|
|
@ -61,14 +61,14 @@ pub struct Socket {
|
||||||
impl Socket {
|
impl Socket {
|
||||||
// TODO: we fix services to 0
|
// TODO: we fix services to 0
|
||||||
/// Construct a new socket
|
/// Construct a new socket
|
||||||
pub fn new(magic: u32) -> Socket {
|
pub fn new(network: constants::Network) -> Socket {
|
||||||
let mut rng = task_rng();
|
let mut rng = task_rng();
|
||||||
Socket {
|
Socket {
|
||||||
stream: None,
|
stream: None,
|
||||||
services: 0,
|
services: 0,
|
||||||
version_nonce: rng.gen(),
|
version_nonce: rng.gen(),
|
||||||
user_agent: String::from_str(constants::USER_AGENT),
|
user_agent: String::from_str(constants::USER_AGENT),
|
||||||
magic: magic
|
magic: constants::magic(network)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue