Skip to content

Commit 51038f5

Browse files
committed
Add alternate network support to Blockchain, UtxoSet, Socket
Still need to do alternate diffchange rules..
1 parent 8f826a9 commit 51038f5

File tree

8 files changed

+128
-48
lines changed

8 files changed

+128
-48
lines changed

src/blockdata/blockchain.rs

+18-7
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ use std::kinds::marker;
3030

3131
use blockdata::block::{Block, BlockHeader};
3232
use blockdata::transaction::Transaction;
33-
use blockdata::constants::{DIFFCHANGE_INTERVAL, DIFFCHANGE_TIMESPAN, max_target};
33+
use blockdata::constants::{DIFFCHANGE_INTERVAL, DIFFCHANGE_TIMESPAN, max_target, genesis_block};
34+
use network::constants::Network;
3435
use network::serialize::{Serializable, SerializeIter};
3536
use util::BitArray;
3637
use util::error::{BitcoinResult, BlockNotFound, DuplicateHash, PrevHashNotFound};
@@ -134,6 +135,7 @@ impl Serializable for Rc<BlockchainNode> {
134135

135136
/// The blockchain
136137
pub struct Blockchain {
138+
network: Network,
137139
tree: BlockTree,
138140
best_tip: Rc<BlockchainNode>,
139141
best_hash: Sha256dHash,
@@ -143,6 +145,7 @@ pub struct Blockchain {
143145
impl Serializable for Blockchain {
144146
fn serialize(&self) -> Vec<u8> {
145147
let mut ret = vec![];
148+
ret.extend(self.network.serialize().move_iter());
146149
ret.extend(self.tree.serialize().move_iter());
147150
ret.extend(self.best_hash.serialize().move_iter());
148151
ret.extend(self.genesis_hash.serialize().move_iter());
@@ -152,7 +155,8 @@ impl Serializable for Blockchain {
152155
fn serialize_iter<'a>(&'a self) -> SerializeIter<'a> {
153156
SerializeIter {
154157
data_iter: None,
155-
sub_iter_iter: box vec![ &self.tree as &Serializable,
158+
sub_iter_iter: box vec![ &self.network as &Serializable,
159+
&self.tree as &Serializable,
156160
&self.best_hash as &Serializable,
157161
&self.genesis_hash as &Serializable ].move_iter(),
158162
sub_iter: None,
@@ -161,6 +165,7 @@ impl Serializable for Blockchain {
161165
}
162166

163167
fn deserialize<I: Iterator<u8>>(mut iter: I) -> IoResult<Blockchain> {
168+
let network: Network = try!(prepend_err("network", Serializable::deserialize(iter.by_ref())));
164169
let tree: BlockTree = try!(prepend_err("tree", Serializable::deserialize(iter.by_ref())));
165170
let best_hash: Sha256dHash = try!(prepend_err("best_hash", Serializable::deserialize(iter.by_ref())));
166171
let genesis_hash: Sha256dHash = try!(prepend_err("genesis_hash", Serializable::deserialize(iter.by_ref())));
@@ -201,6 +206,7 @@ impl Serializable for Blockchain {
201206
} else {
202207
// Return the chain
203208
Ok(Blockchain {
209+
network: network,
204210
tree: tree,
205211
best_tip: best.clone(),
206212
best_hash: best_hash,
@@ -367,7 +373,8 @@ fn satoshi_the_precision(n: &Uint256) -> Uint256 {
367373

368374
impl Blockchain {
369375
/// Constructs a new blockchain
370-
pub fn new(genesis: Block) -> Blockchain {
376+
pub fn new(network: Network) -> Blockchain {
377+
let genesis = genesis_block(network);
371378
let genhash = genesis.header.hash();
372379
let rc_gen = Rc::new(BlockchainNode {
373380
total_work: Zero::zero(),
@@ -379,6 +386,7 @@ impl Blockchain {
379386
next: RefCell::new(None)
380387
});
381388
Blockchain {
389+
network: network,
382390
tree: {
383391
let mut pat = PatriciaTree::new();
384392
pat.insert(&genhash.as_uint256(), 256, rc_gen.clone());
@@ -479,7 +487,7 @@ impl Blockchain {
479487
target = target.mul_u32(timespan);
480488
target = target / FromPrimitive::from_u64(DIFFCHANGE_TIMESPAN as u64).unwrap();
481489
// Clamp below MAX_TARGET (difficulty 1)
482-
let max = max_target();
490+
let max = max_target(self.network);
483491
if target > max { target = max };
484492
// Compactify (make expressible in the 8+24 nBits float format
485493
satoshi_the_precision(&target)
@@ -601,20 +609,23 @@ mod tests {
601609

602610
use blockdata::blockchain::Blockchain;
603611
use blockdata::constants::genesis_block;
612+
use network::constants::Bitcoin;
604613
use network::serialize::Serializable;
605614

606615
#[test]
607616
fn blockchain_serialize_test() {
608-
let empty_chain = Blockchain::new(genesis_block());
609-
assert_eq!(empty_chain.best_tip.hash().serialize(), genesis_block().header.hash().serialize());
617+
let empty_chain = Blockchain::new(Bitcoin);
618+
assert_eq!(empty_chain.best_tip.hash().serialize(),
619+
genesis_block(Bitcoin).header.hash().serialize());
610620

611621
let serial = empty_chain.serialize();
612622
assert_eq!(serial, empty_chain.serialize_iter().collect());
613623

614624
let deserial: IoResult<Blockchain> = Serializable::deserialize(serial.iter().map(|n| *n));
615625
assert!(deserial.is_ok());
616626
let read_chain = deserial.unwrap();
617-
assert_eq!(read_chain.best_tip.hash().serialize(), genesis_block().header.hash().serialize());
627+
assert_eq!(read_chain.best_tip.hash().serialize(),
628+
genesis_block(Bitcoin).header.hash().serialize());
618629
}
619630
}
620631

src/blockdata/constants.rs

+59-26
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
//! single transaction
2020
//!
2121
22+
use network::constants::{Network, Bitcoin, BitcoinTestnet};
23+
2224
use std::num::from_u64;
2325

2426
use blockdata::opcodes;
@@ -35,12 +37,12 @@ pub static DIFFCHANGE_INTERVAL: u32 = 2016;
3537
pub static DIFFCHANGE_TIMESPAN: u32 = 14 * 24 * 3600;
3638

3739
/// In Bitcoind this is insanely described as ~((u256)0 >> 32)
38-
pub fn max_target() -> Uint256 {
40+
pub fn max_target(_: Network) -> Uint256 {
3941
from_u64::<Uint256>(0xFFFF).unwrap() << 208u
4042
}
4143

42-
/// Constructs and returns the coinbase (and only) transaction of the genesis block
43-
pub fn genesis_tx() -> Transaction {
44+
/// Constructs and returns the coinbase (and only) transaction of the Bitcoin genesis block
45+
fn bitcoin_genesis_tx() -> Transaction {
4446
// Base
4547
let mut ret = Transaction {
4648
version: 1,
@@ -75,34 +77,51 @@ pub fn genesis_tx() -> Transaction {
7577
}
7678

7779
/// Constructs and returns the genesis block
78-
pub fn genesis_block() -> Block {
79-
let txdata = vec![genesis_tx()];
80-
let header = BlockHeader {
81-
version: 1,
82-
prev_blockhash: zero_hash(),
83-
merkle_root: merkle_root(txdata.as_slice()),
84-
time: 1231006505,
85-
bits: 0x1d00ffff,
86-
nonce: 2083236893
87-
};
88-
89-
Block {
90-
header: header,
91-
txdata: txdata
80+
pub fn genesis_block(network: Network) -> Block {
81+
match network {
82+
Bitcoin => {
83+
let txdata = vec![bitcoin_genesis_tx()];
84+
Block {
85+
header: BlockHeader {
86+
version: 1,
87+
prev_blockhash: zero_hash(),
88+
merkle_root: merkle_root(txdata.as_slice()),
89+
time: 1231006505,
90+
bits: 0x1d00ffff,
91+
nonce: 2083236893
92+
},
93+
txdata: txdata
94+
}
95+
}
96+
BitcoinTestnet => {
97+
let txdata = vec![bitcoin_genesis_tx()];
98+
Block {
99+
header: BlockHeader {
100+
version: 1,
101+
prev_blockhash: zero_hash(),
102+
merkle_root: merkle_root(txdata.as_slice()),
103+
time: 1296688602,
104+
bits: 0x1d00ffff,
105+
nonce: 414098458
106+
},
107+
txdata: txdata
108+
}
109+
}
92110
}
93111
}
94112

95113
#[cfg(test)]
96114
mod test {
97115
use network::serialize::Serializable;
98-
use blockdata::constants::{genesis_block, genesis_tx};
116+
use network::constants::{Bitcoin, BitcoinTestnet};
117+
use blockdata::constants::{genesis_block, bitcoin_genesis_tx};
99118
use blockdata::constants::{MAX_SEQUENCE, COIN_VALUE};
100119
use util::misc::hex_bytes;
101120
use util::hash::zero_hash;
102121

103122
#[test]
104-
fn genesis_first_transaction() {
105-
let gen = genesis_tx();
123+
fn bitcoin_genesis_first_transaction() {
124+
let gen = bitcoin_genesis_tx();
106125

107126
assert_eq!(gen.version, 1);
108127
assert_eq!(gen.input.len(), 1);
@@ -123,18 +142,32 @@ mod test {
123142
}
124143

125144
#[test]
126-
fn genesis_full_block() {
127-
let gen = genesis_block();
145+
fn bitcoin_genesis_full_block() {
146+
let gen = genesis_block(Bitcoin);
128147

129148
assert_eq!(gen.header.version, 1);
130149
assert_eq!(gen.header.prev_blockhash.as_slice(), zero_hash().as_slice());
131-
assert_eq!(gen.header.merkle_root.serialize().iter().rev().map(|n| *n).collect::<Vec<u8>>(),
132-
hex_bytes("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b").unwrap());
150+
assert_eq!(gen.header.merkle_root.le_hex_string(),
151+
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".to_string());
133152
assert_eq!(gen.header.time, 1231006505);
134153
assert_eq!(gen.header.bits, 0x1d00ffff);
135154
assert_eq!(gen.header.nonce, 2083236893);
136-
assert_eq!(gen.header.hash().serialize().iter().rev().map(|n| *n).collect::<Vec<u8>>(),
137-
hex_bytes("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f").unwrap());
155+
assert_eq!(gen.header.hash().le_hex_string(),
156+
"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f".to_string());
157+
}
158+
159+
#[test]
160+
fn testnet_genesis_full_block() {
161+
let gen = genesis_block(BitcoinTestnet);
162+
assert_eq!(gen.header.version, 1);
163+
assert_eq!(gen.header.prev_blockhash.as_slice(), zero_hash().as_slice());
164+
assert_eq!(gen.header.merkle_root.le_hex_string(),
165+
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".to_string());
166+
assert_eq!(gen.header.time, 1296688602);
167+
assert_eq!(gen.header.bits, 0x1d00ffff);
168+
assert_eq!(gen.header.nonce, 414098458);
169+
assert_eq!(gen.header.hash().le_hex_string(),
170+
"000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943".to_string());
138171
}
139172
}
140173

src/blockdata/utxoset.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ use std::io::IoResult;
2222
use std::mem;
2323

2424
use blockdata::transaction::{Transaction, TxOut};
25+
use blockdata::constants::genesis_block;
2526
use blockdata::block::Block;
27+
use network::constants::Network;
2628
use network::serialize::{Serializable, SerializeIter};
2729
use util::hash::Sha256dHash;
2830
use util::uint::Uint128;
@@ -51,14 +53,14 @@ impl_serializable!(UtxoSet, last_hash, n_utxos, spent_txos, spent_idx, tree)
5153

5254
impl UtxoSet {
5355
/// Constructs a new UTXO set
54-
pub fn new(genesis: Block, rewind_limit: uint) -> UtxoSet {
56+
pub fn new(network: Network, rewind_limit: uint) -> UtxoSet {
5557
// There is in fact a transaction in the genesis block, but the Bitcoin
5658
// reference client does not add its sole output to the UTXO set. We
5759
// must follow suit, otherwise we will accept a transaction spending it
5860
// while the reference client won't, causing us to fork off the network.
5961
UtxoSet {
6062
tree: PatriciaTree::new(),
61-
last_hash: genesis.header.hash(),
63+
last_hash: genesis_block(network).header.hash(),
6264
spent_txos: Vec::from_elem(rewind_limit, vec![]),
6365
spent_idx: 0,
6466
n_utxos: 0
@@ -270,14 +272,14 @@ mod tests {
270272
use std::io::IoResult;
271273
use serialize::hex::FromHex;
272274

273-
use blockdata::constants::genesis_block;
274275
use blockdata::block::Block;
275276
use blockdata::utxoset::UtxoSet;
277+
use network::constants::Bitcoin;
276278
use network::serialize::Serializable;
277279

278280
#[test]
279281
fn utxoset_serialize_test() {
280-
let mut empty_set = UtxoSet::new(genesis_block(), 100);
282+
let mut empty_set = UtxoSet::new(Bitcoin, 100);
281283

282284
let new_block: Block = Serializable::deserialize("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b0201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d026e04ffffffff0100f2052a0100000043410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac00000000010000000321f75f3139a013f50f315b23b0c9a2b6eac31e2bec98e5891c924664889942260000000049483045022100cb2c6b346a978ab8c61b18b5e9397755cbd17d6eb2fe0083ef32e067fa6c785a02206ce44e613f31d9a6b0517e46f3db1576e9812cc98d159bfdaf759a5014081b5c01ffffffff79cda0945903627c3da1f85fc95d0b8ee3e76ae0cfdc9a65d09744b1f8fc85430000000049483045022047957cdd957cfd0becd642f6b84d82f49b6cb4c51a91f49246908af7c3cfdf4a022100e96b46621f1bffcf5ea5982f88cef651e9354f5791602369bf5a82a6cd61a62501fffffffffe09f5fe3ffbf5ee97a54eb5e5069e9da6b4856ee86fc52938c2f979b0f38e82000000004847304402204165be9a4cbab8049e1af9723b96199bfd3e85f44c6b4c0177e3962686b26073022028f638da23fc003760861ad481ead4099312c60030d4cb57820ce4d33812a5ce01ffffffff01009d966b01000000434104ea1feff861b51fe3f5f8a3b12d0f4712db80e919548a80839fc47c6a21e66d957e9c5d8cd108c7a2d2324bad71f9904ac0ae7336507d785b17a2c115e427a32fac00000000".from_hex().unwrap().iter().map(|n| *n)).unwrap();
283285

src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,3 @@ pub mod network;
6262
pub mod blockdata;
6363
pub mod util;
6464

65-

src/network/constants.rs

+39-2
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,47 @@
1818
//! protocol, such as protocol versioning and magic header bytes.
1919
//!
2020
21-
pub static MAGIC_BITCOIN: u32 = 0xD9B4BEF9;
22-
pub static MAGIC_TESTNET: u32 = 0x0709110B;
21+
use std::io::{IoResult, InvalidInput, standard_error};
22+
23+
use network::serialize::Serializable;
24+
use util::misc::prepend_err;
25+
26+
/// The cryptocurrency to operate on
27+
#[deriving(PartialEq, Eq, Clone, Show)]
28+
pub enum Network {
29+
/// Classic Bitcoin
30+
Bitcoin,
31+
/// Bitcoin's testnet
32+
BitcoinTestnet,
33+
}
2334

2435
pub static PROTOCOL_VERSION: u32 = 70001;
2536
pub static SERVICES: u64 = 0;
2637
pub static USER_AGENT: &'static str = "bitcoin-rust v0.1";
2738

39+
/// Return the network magic bytes, which should be encoded little-endian
40+
/// at the start of every message
41+
pub fn magic(network: Network) -> u32 {
42+
match network {
43+
Bitcoin => 0xD9B4BEF9,
44+
BitcoinTestnet => 0x0709110B
45+
// Note: any new entries here must be added to `deserialize` below
46+
}
47+
}
48+
49+
// This affects the representation of the `Network` in text files
50+
impl Serializable for Network {
51+
fn serialize(&self) -> Vec<u8> {
52+
magic(*self).serialize()
53+
}
54+
55+
fn deserialize<I: Iterator<u8>>(iter: I) -> IoResult<Network> {
56+
let magic: u32 = try!(prepend_err("magic", Serializable::deserialize(iter)));
57+
match magic {
58+
0xD9B4BEF9 => Ok(Bitcoin),
59+
0x0709110B => Ok(BitcoinTestnet),
60+
_ => Err(standard_error(InvalidInput))
61+
}
62+
}
63+
}
64+

src/network/listener.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use std::io::{IoResult, standard_error, ConnectionFailed};
2222
use std::io::timer;
2323

24+
use network::constants::Network;
2425
use network::message::{NetworkMessage, Verack};
2526
use network::socket::Socket;
2627

@@ -30,12 +31,12 @@ pub trait Listener {
3031
fn peer<'a>(&'a self) -> &'a str;
3132
/// Return the port we have connected to the peer on
3233
fn port(&self) -> u16;
33-
/// Return the network magic
34-
fn magic(&self) -> u32;
34+
/// Return the network this `Listener` is operating on
35+
fn network(&self) -> Network;
3536
/// Main listen loop
3637
fn start(&self) -> IoResult<(Receiver<NetworkMessage>, Socket)> {
3738
// Open socket
38-
let mut ret_sock = Socket::new(self.magic());
39+
let mut ret_sock = Socket::new(self.network());
3940
match ret_sock.connect(self.peer(), self.port()) {
4041
Ok(_) => {},
4142
Err(_) => return Err(standard_error(ConnectionFailed))

src/network/serialize.rs

-3
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,6 @@ impl<'a> Iterator<u8> for SerializeIter<'a> {
7676
}
7777
}
7878

79-
/// A string which must be encoded as 12 bytes, used in network message headers
80-
81-
8279
#[deriving(PartialEq, Clone, Show)]
8380
/// Data which must be preceded by a 4-byte checksum
8481
pub struct CheckedData(pub Vec<u8>);

src/network/socket.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,14 @@ pub struct Socket {
6161
impl Socket {
6262
// TODO: we fix services to 0
6363
/// Construct a new socket
64-
pub fn new(magic: u32) -> Socket {
64+
pub fn new(network: constants::Network) -> Socket {
6565
let mut rng = task_rng();
6666
Socket {
6767
stream: None,
6868
services: 0,
6969
version_nonce: rng.gen(),
7070
user_agent: String::from_str(constants::USER_AGENT),
71-
magic: magic
71+
magic: constants::magic(network)
7272
}
7373
}
7474

0 commit comments

Comments
 (0)