This commit is contained in:
Svyatoslav Nikolsky 2018-05-18 09:54:06 +03:00
parent da0c55db7a
commit 7e47bd3b28
49 changed files with 329 additions and 171 deletions

1
Cargo.lock generated
View File

@ -720,6 +720,7 @@ dependencies = [
"chain 0.1.0", "chain 0.1.0",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"primitives 0.1.0", "primitives 0.1.0",
"serialization 0.1.0",
] ]
[[package]] [[package]]

View File

@ -60,6 +60,8 @@ impl Block {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use rustc_serialize::hex::FromHex;
use ser::{set_default_flags, serialize_with_flags, deserialize_with_flags, SERIALIZE_ZCASH, DESERIALIZE_ZCASH};
use hash::H256; use hash::H256;
use super::Block; use super::Block;
@ -74,4 +76,20 @@ mod tests {
assert_eq!(block.merkle_root(), merkle_root); assert_eq!(block.merkle_root(), merkle_root);
assert_eq!(block.hash(), hash); assert_eq!(block.hash(), hash);
} }
#[test]
fn zcash_genesis_block_is_parsed() {
set_default_flags(SERIALIZE_ZCASH);
let origin_hash = H256::from_reversed_str("00040fe8ec8471911baa1db1266ea15dd06b4a8a5c453883c000b031973dce08");
let origin = "040000000000000000000000000000000000000000000000000000000000000000000000db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac4000000000000000000000000000000000000000000000000000000000000000090041358ffff071f5712000000000000000000000000000000000000000000000000000000000000fd4005000a889f00854b8665cd555f4656f68179d31ccadc1b1f7fb0952726313b16941da348284d67add4686121d4e3d930160c1348d8191c25f12b267a6a9c131b5031cbf8af1f79c9d513076a216ec87ed045fa966e01214ed83ca02dc1797270a454720d3206ac7d931a0a680c5c5e099057592570ca9bdf6058343958b31901fce1a15a4f38fd347750912e14004c73dfe588b903b6c03166582eeaf30529b14072a7b3079e3a684601b9b3024054201f7440b0ee9eb1a7120ff43f713735494aa27b1f8bab60d7f398bca14f6abb2adbf29b04099121438a7974b078a11635b594e9170f1086140b4173822dd697894483e1c6b4e8b8dcd5cb12ca4903bc61e108871d4d915a9093c18ac9b02b6716ce1013ca2c1174e319c1a570215bc9ab5f7564765f7be20524dc3fdf8aa356fd94d445e05ab165ad8bb4a0db096c097618c81098f91443c719416d39837af6de85015dca0de89462b1d8386758b2cf8a99e00953b308032ae44c35e05eb71842922eb69797f68813b59caf266cb6c213569ae3280505421a7e3a0a37fdf8e2ea354fc5422816655394a9454bac542a9298f176e211020d63dee6852c40de02267e2fc9d5e1ff2ad9309506f02a1a71a0501b16d0d36f70cdfd8de78116c0c506ee0b8ddfdeb561acadf31746b5a9dd32c21930884397fb1682164cb565cc14e089d66635a32618f7eb05fe05082b8a3fae620571660a6b89886eac53dec109d7cbb6930ca698a168f301a950be152da1be2b9e07516995e20baceebecb5579d7cdbc16d09f3a50cb3c7dffe33f26686d4ff3f8946ee6475e98cf7b3cf9062b6966e838f865ff3de5fb064a37a21da7bb8dfd2501a29e184f207caaba364f36f2329a77515dcb710e29ffbf73e2bbd773fab1f9a6b005567affff605c132e4e4dd69f36bd201005458cfbd2c658701eb2a700251cefd886b1e674ae816d3f719bac64be649c172ba27a4fd55947d95d53ba4cbc73de97b8af5ed4840b659370c556e7376457f51e5ebb66018849923db82c1c9a819f173cccdb8f3324b239609a300018d0fb094adf5bd7cbb3834c69e6d0b3798065c525b20f040e965e1a161af78ff7561cd874f5f1b75aa0bc77f720589e1b810f831eac5073e6dd46d00a2793f70f7427f0f798f2f53a67e615e65d356e66fe40609a958a05edb4c175bcc383ea0530e67ddbe479a898943c6e3074c6fcc252d6014de3a3d292b03f0d88d312fe221be7be7e3c59d07fa0f2f4029e364f1f355c5d01fa53770d0cd76d82bf7e60f6903bc1beb772e6fde4a70be51d9c7e03c8d6d8dfb361a234ba47c470fe630820bbd920715621b9fbedb49fcee165ead0875e6c2b1af16f50b5d6140cc981122fcbcf7c5a4e3772b3661b628e08380abc545957e59f634705b1bbde2f0b4e055a5ec5676d859be77e20962b645e051a880fddb0180b4555789e1f9344a436a84dc5579e2553f1e5fb0a599c137be36cabbed0319831fea3fddf94ddc7971e4bcf02cdc93294a9aab3e3b13e3b058235b4f4ec06ba4ceaa49d675b4ba80716f3bc6976b1fbf9c8bf1f3e3a4dc1cd83ef9cf816667fb94f1e923ff63fef072e6a19321e4812f96cb0ffa864da50ad74deb76917a336f31dce03ed5f0303aad5e6a83634f9fcc371096f8288b8f02ddded5ff1bb9d49331e4a84dbe1543164438fde9ad71dab024779dcdde0b6602b5ae0a6265c14b94edd83b37403f4b78fcd2ed555b596402c28ee81d87a909c4e8722b30c71ecdd861b05f61f8b1231795c76adba2fdefa451b283a5d527955b9f3de1b9828e7b2e74123dd47062ddcc09b05e7fa13cb2212a6fdbc65d7e852cec463ec6fd929f5b8483cf3052113b13dac91b69f49d1b7d1aec01c4a68e41ce1570101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff071f0104455a6361736830623963346565663862376363343137656535303031653335303039383462366665613335363833613763616331343161303433633432303634383335643334ffffffff010000000000000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000";
let origin = origin.from_hex().unwrap();
let parsed: Block = deserialize_with_flags(&origin as &[u8], DESERIALIZE_ZCASH).unwrap();
let serialized = serialize_with_flags(&parsed, SERIALIZE_ZCASH).take();
assert_eq!(origin, serialized);
let parsed_hash = parsed.hash();
assert_eq!(origin_hash, parsed_hash);
}
} }

View File

@ -61,7 +61,7 @@ impl From<&'static str> for BlockHeader {
impl Serializable for BlockHeader { impl Serializable for BlockHeader {
fn serialize(&self, stream: &mut Stream) { fn serialize(&self, stream: &mut Stream) {
let is_zcash_format = stream.is_zcash_stream(); let is_zcash_format = stream.is_zcash_stream();
println!("=== is_zcash_format = {}", is_zcash_format);
stream stream
.append(&self.version) .append(&self.version)
.append(&self.previous_header_hash) .append(&self.previous_header_hash)
@ -140,7 +140,7 @@ mod tests {
equihash_solution: None, equihash_solution: None,
}; };
let mut stream = Stream::default(); let mut stream = Stream::new();
stream.append(&block_header); stream.append(&block_header);
let expected = vec![ let expected = vec![
@ -166,7 +166,7 @@ mod tests {
6, 0, 0, 0, 6, 0, 0, 0,
]; ];
let mut reader = Reader::new(&buffer); let mut reader = Reader::new(&buffer, 0);
let expected = BlockHeader { let expected = BlockHeader {
version: 1, version: 1,

View File

@ -2,7 +2,7 @@ use ser::Stream;
use bytes::{TaggedBytes, Bytes}; use bytes::{TaggedBytes, Bytes};
use network::Magic; use network::Magic;
use common::Command; use common::Command;
use serialization::serialize_payload_with_flags; use serialization::serialize_payload;
use {Payload, MessageResult, MessageHeader}; use {Payload, MessageResult, MessageHeader};
pub fn to_raw_message(magic: Magic, command: Command, payload: &Bytes) -> Bytes { pub fn to_raw_message(magic: Magic, command: Command, payload: &Bytes) -> Bytes {
@ -22,8 +22,8 @@ impl<T> Message<T> where T: Payload {
Self::with_flags(magic, version, payload, 0) Self::with_flags(magic, version, payload, 0)
} }
pub fn with_flags(magic: Magic, version: u32, payload: &T, serialization_flags: u32) -> MessageResult<Self> { pub fn with_flags(magic: Magic, version: u32, payload: &T, flags: u32) -> MessageResult<Self> {
let serialized = try!(serialize_payload_with_flags(payload, version, serialization_flags)); let serialized = try!(serialize_payload(payload, version, flags));
let message = Message { let message = Message {
bytes: TaggedBytes::new(to_raw_message(magic, T::command().into(), &serialized)), bytes: TaggedBytes::new(to_raw_message(magic, T::command().into(), &serialized)),

View File

@ -25,12 +25,12 @@ impl MessageHeader {
} }
impl MessageHeader { impl MessageHeader {
pub fn deserialize(data: &[u8], expected: Magic) -> Result<Self, Error> { pub fn deserialize(data: &[u8], flags: u32, expected: Magic) -> Result<Self, Error> {
if data.len() != 24 { if data.len() != 24 {
return Err(Error::Deserialize); return Err(Error::Deserialize);
} }
let mut reader = Reader::new(data); let mut reader = Reader::new(data, flags);
let magic: u32 = try!(reader.read()); let magic: u32 = try!(reader.read());
let magic = Magic::from(magic); let magic = Magic::from(magic);
if expected != magic { if expected != magic {
@ -88,6 +88,6 @@ mod tests {
checksum: "ed52399b".into(), checksum: "ed52399b".into(),
}; };
assert_eq!(expected, MessageHeader::deserialize(&raw, Network::Mainnet.magic(&ConsensusFork::BitcoinCore)).unwrap()); assert_eq!(expected, MessageHeader::deserialize(&raw, 0, Network::Mainnet.magic(&ConsensusFork::BitcoinCore)).unwrap());
} }
} }

View File

@ -1,5 +1,5 @@
mod stream; mod stream;
mod reader; mod reader;
pub use self::stream::{serialize_payload, serialize_payload_with_flags}; pub use self::stream::serialize_payload;
pub use self::reader::deserialize_payload; pub use self::reader::deserialize_payload;

View File

@ -1,8 +1,8 @@
use ser::Reader; use ser::Reader;
use {Payload, Error}; use {Payload, Error};
pub fn deserialize_payload<T>(buffer: &[u8], version: u32) -> Result<T, Error> where T: Payload { pub fn deserialize_payload<T>(buffer: &[u8], version: u32, flags: u32) -> Result<T, Error> where T: Payload {
let mut reader = PayloadReader::new(buffer, version); let mut reader = PayloadReader::new(buffer, version, flags);
let result = try!(reader.read()); let result = try!(reader.read());
if !reader.is_finished() { if !reader.is_finished() {
return Err(Error::Deserialize); return Err(Error::Deserialize);
@ -17,9 +17,9 @@ pub struct PayloadReader<T> {
} }
impl<'a> PayloadReader<&'a [u8]> { impl<'a> PayloadReader<&'a [u8]> {
pub fn new(buffer: &'a [u8], version: u32) -> Self { pub fn new(buffer: &'a [u8], version: u32, flags: u32) -> Self {
PayloadReader { PayloadReader {
reader: Reader::new(buffer), reader: Reader::new(buffer, flags),
version: version, version: version,
} }
} }

View File

@ -2,12 +2,8 @@ use bytes::Bytes;
use ser::Stream; use ser::Stream;
use {Payload, Error, MessageResult}; use {Payload, Error, MessageResult};
pub fn serialize_payload<T>(t: &T, version: u32) -> MessageResult<Bytes> where T: Payload { pub fn serialize_payload<T>(t: &T, version: u32, flags: u32) -> MessageResult<Bytes> where T: Payload {
serialize_payload_with_flags(t, version, 0) let mut stream = PayloadStream::new(version, flags);
}
pub fn serialize_payload_with_flags<T>(t: &T, version: u32, serialization_flags: u32) -> MessageResult<Bytes> where T: Payload {
let mut stream = PayloadStream::new(version, serialization_flags);
try!(stream.append(t)); try!(stream.append(t));
Ok(stream.out()) Ok(stream.out())
} }
@ -18,9 +14,9 @@ pub struct PayloadStream {
} }
impl PayloadStream { impl PayloadStream {
pub fn new(version: u32, serialization_flags: u32) -> Self { pub fn new(version: u32, flags: u32) -> Self {
PayloadStream { PayloadStream {
stream: Stream::with_flags(serialization_flags), stream: Stream::with_flags(flags),
version: version, version: version,
} }
} }

View File

@ -196,7 +196,7 @@ impl Deserializable for V70001 {
impl From<&'static str> for Version { impl From<&'static str> for Version {
fn from(s: &'static str) -> Self { fn from(s: &'static str) -> Self {
let bytes: Bytes = s.into(); let bytes: Bytes = s.into();
deserialize_payload(&bytes, 0).unwrap() deserialize_payload(&bytes, 0, 0).unwrap()
} }
} }
@ -222,7 +222,7 @@ mod test {
start_height: 98645, start_height: 98645,
}); });
assert_eq!(serialize_payload(&version, 0), Ok(expected)); assert_eq!(serialize_payload(&version, 0, 0), Ok(expected));
} }
#[test] #[test]
@ -241,6 +241,6 @@ mod test {
start_height: 98645, start_height: 98645,
}); });
assert_eq!(expected, deserialize_payload(&raw, 0).unwrap()); assert_eq!(expected, deserialize_payload(&raw, 0, 0).unwrap());
} }
} }

View File

@ -7,3 +7,4 @@ authors = ["debris <marek.kotewicz@gmail.com>"]
lazy_static = "1.0" lazy_static = "1.0"
chain = { path = "../chain" } chain = { path = "../chain" }
primitives = { path = "../primitives" } primitives = { path = "../primitives" }
serialization = { path = "../serialization" }

View File

@ -3,6 +3,7 @@ extern crate lazy_static;
extern crate chain; extern crate chain;
extern crate primitives; extern crate primitives;
extern crate serialization;
mod consensus; mod consensus;
mod deployments; mod deployments;

View File

@ -16,6 +16,10 @@ const BITCOIN_CASH_MAGIC_MAINNET: u32 = 0xE8F3E1E3;
const BITCOIN_CASH_MAGIC_TESTNET: u32 = 0xF4F3E5F4; const BITCOIN_CASH_MAGIC_TESTNET: u32 = 0xF4F3E5F4;
const BITCOIN_CASH_MAGIC_REGTEST: u32 = 0xFABFB5DA; const BITCOIN_CASH_MAGIC_REGTEST: u32 = 0xFABFB5DA;
const ZCASH_MAGIC_MAINNET: u32 = 0x6427e924;
const ZCASH_MAGIC_TESTNET: u32 = 0xbff91afa;
const ZCASH_MAGIC_REGTEST: u32 = 0x5f3fe8aa;
lazy_static! { lazy_static! {
static ref MAX_BITS_MAINNET: U256 = "00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff".parse() static ref MAX_BITS_MAINNET: U256 = "00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff".parse()
.expect("hardcoded value should parse without errors"); .expect("hardcoded value should parse without errors");
@ -23,6 +27,13 @@ lazy_static! {
.expect("hardcoded value should parse without errors"); .expect("hardcoded value should parse without errors");
static ref MAX_BITS_REGTEST: U256 = "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".parse() static ref MAX_BITS_REGTEST: U256 = "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".parse()
.expect("hardcoded value should parse without errors"); .expect("hardcoded value should parse without errors");
static ref ZCASH_MAX_BITS_MAINNET: U256 = "0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".parse()
.expect("hardcoded value should parse without errors");
static ref ZCASH_MAX_BITS_TESTNET: U256 = "07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".parse()
.expect("hardcoded value should parse without errors");
static ref ZCASH_MAX_BITS_REGTEST: U256 = "0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f".parse()
.expect("hardcoded value should parse without errors");
} }
/// Network magic type. /// Network magic type.
@ -49,6 +60,9 @@ impl Network {
(&ConsensusFork::BitcoinCash(_), Network::Mainnet) => BITCOIN_CASH_MAGIC_MAINNET, (&ConsensusFork::BitcoinCash(_), Network::Mainnet) => BITCOIN_CASH_MAGIC_MAINNET,
(&ConsensusFork::BitcoinCash(_), Network::Testnet) => BITCOIN_CASH_MAGIC_TESTNET, (&ConsensusFork::BitcoinCash(_), Network::Testnet) => BITCOIN_CASH_MAGIC_TESTNET,
(&ConsensusFork::BitcoinCash(_), Network::Regtest) => BITCOIN_CASH_MAGIC_REGTEST, (&ConsensusFork::BitcoinCash(_), Network::Regtest) => BITCOIN_CASH_MAGIC_REGTEST,
(&ConsensusFork::ZCash, Network::Mainnet) => ZCASH_MAGIC_MAINNET,
(&ConsensusFork::ZCash, Network::Testnet) => ZCASH_MAGIC_TESTNET,
(&ConsensusFork::ZCash, Network::Regtest) => ZCASH_MAGIC_REGTEST,
(_, Network::Mainnet) => MAGIC_MAINNET, (_, Network::Mainnet) => MAGIC_MAINNET,
(_, Network::Testnet) => MAGIC_TESTNET, (_, Network::Testnet) => MAGIC_TESTNET,
(_, Network::Regtest) => MAGIC_REGTEST, (_, Network::Regtest) => MAGIC_REGTEST,
@ -57,20 +71,26 @@ impl Network {
} }
} }
pub fn max_bits(&self) -> U256 { pub fn max_bits(&self, fork: &ConsensusFork) -> U256 {
match *self { match (fork, *self) {
Network::Mainnet | Network::Other(_) => MAX_BITS_MAINNET.clone(), (&ConsensusFork::ZCash, Network::Mainnet) => ZCASH_MAX_BITS_MAINNET.clone(),
Network::Testnet => MAX_BITS_TESTNET.clone(), (&ConsensusFork::ZCash, Network::Testnet) => ZCASH_MAX_BITS_TESTNET.clone(),
Network::Regtest => MAX_BITS_REGTEST.clone(), (&ConsensusFork::ZCash, Network::Testnet) => ZCASH_MAX_BITS_REGTEST.clone(),
Network::Unitest => Compact::max_value().into(), (_, Network::Mainnet) | (_, Network::Other(_)) => MAX_BITS_MAINNET.clone(),
(_, Network::Testnet) => MAX_BITS_TESTNET.clone(),
(_, Network::Regtest) => MAX_BITS_REGTEST.clone(),
(_, Network::Unitest) => Compact::max_value().into(),
} }
} }
pub fn port(&self) -> u16 { pub fn port(&self, fork: &ConsensusFork) -> u16 {
match *self { match (fork, *self) {
Network::Mainnet | Network::Other(_) => 8333, (&ConsensusFork::ZCash, Network::Mainnet) | (&ConsensusFork::ZCash, Network::Other(_)) => 8233,
Network::Testnet => 18333, (&ConsensusFork::ZCash, Network::Testnet) => 18233,
Network::Regtest | Network::Unitest => 18444, (&ConsensusFork::ZCash, Network::Regtest) | (&ConsensusFork::ZCash, Network::Unitest) => 18344,
(_, Network::Mainnet) | (_, Network::Other(_)) => 8333,
(_, Network::Testnet) => 18333,
(_, Network::Regtest) | (_, Network::Unitest) => 18444,
} }
} }
@ -82,19 +102,35 @@ impl Network {
} }
} }
pub fn genesis_block(&self) -> Block { pub fn genesis_block(&self, fork: &ConsensusFork) -> Block {
match *self { match (fork, *self) {
Network::Mainnet | Network::Other(_) => "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000".into(), // TODO
Network::Testnet => "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff001d1aa4ae180101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000".into(), (&ConsensusFork::ZCash, Network::Mainnet) | (&ConsensusFork::ZCash, Network::Other(_)) => {
Network::Regtest | Network::Unitest => "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff7f20020000000101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000".into(), use serialization;
use chain;
use chain::hex::FromHex;
let origin = "040000000000000000000000000000000000000000000000000000000000000000000000db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac4000000000000000000000000000000000000000000000000000000000000000090041358ffff071f5712000000000000000000000000000000000000000000000000000000000000fd4005000a889f00854b8665cd555f4656f68179d31ccadc1b1f7fb0952726313b16941da348284d67add4686121d4e3d930160c1348d8191c25f12b267a6a9c131b5031cbf8af1f79c9d513076a216ec87ed045fa966e01214ed83ca02dc1797270a454720d3206ac7d931a0a680c5c5e099057592570ca9bdf6058343958b31901fce1a15a4f38fd347750912e14004c73dfe588b903b6c03166582eeaf30529b14072a7b3079e3a684601b9b3024054201f7440b0ee9eb1a7120ff43f713735494aa27b1f8bab60d7f398bca14f6abb2adbf29b04099121438a7974b078a11635b594e9170f1086140b4173822dd697894483e1c6b4e8b8dcd5cb12ca4903bc61e108871d4d915a9093c18ac9b02b6716ce1013ca2c1174e319c1a570215bc9ab5f7564765f7be20524dc3fdf8aa356fd94d445e05ab165ad8bb4a0db096c097618c81098f91443c719416d39837af6de85015dca0de89462b1d8386758b2cf8a99e00953b308032ae44c35e05eb71842922eb69797f68813b59caf266cb6c213569ae3280505421a7e3a0a37fdf8e2ea354fc5422816655394a9454bac542a9298f176e211020d63dee6852c40de02267e2fc9d5e1ff2ad9309506f02a1a71a0501b16d0d36f70cdfd8de78116c0c506ee0b8ddfdeb561acadf31746b5a9dd32c21930884397fb1682164cb565cc14e089d66635a32618f7eb05fe05082b8a3fae620571660a6b89886eac53dec109d7cbb6930ca698a168f301a950be152da1be2b9e07516995e20baceebecb5579d7cdbc16d09f3a50cb3c7dffe33f26686d4ff3f8946ee6475e98cf7b3cf9062b6966e838f865ff3de5fb064a37a21da7bb8dfd2501a29e184f207caaba364f36f2329a77515dcb710e29ffbf73e2bbd773fab1f9a6b005567affff605c132e4e4dd69f36bd201005458cfbd2c658701eb2a700251cefd886b1e674ae816d3f719bac64be649c172ba27a4fd55947d95d53ba4cbc73de97b8af5ed4840b659370c556e7376457f51e5ebb66018849923db82c1c9a819f173cccdb8f3324b239609a300018d0fb094adf5bd7cbb3834c69e6d0b3798065c525b20f040e965e1a161af78ff7561cd874f5f1b75aa0bc77f720589e1b810f831eac5073e6dd46d00a2793f70f7427f0f798f2f53a67e615e65d356e66fe40609a958a05edb4c175bcc383ea0530e67ddbe479a898943c6e3074c6fcc252d6014de3a3d292b03f0d88d312fe221be7be7e3c59d07fa0f2f4029e364f1f355c5d01fa53770d0cd76d82bf7e60f6903bc1beb772e6fde4a70be51d9c7e03c8d6d8dfb361a234ba47c470fe630820bbd920715621b9fbedb49fcee165ead0875e6c2b1af16f50b5d6140cc981122fcbcf7c5a4e3772b3661b628e08380abc545957e59f634705b1bbde2f0b4e055a5ec5676d859be77e20962b645e051a880fddb0180b4555789e1f9344a436a84dc5579e2553f1e5fb0a599c137be36cabbed0319831fea3fddf94ddc7971e4bcf02cdc93294a9aab3e3b13e3b058235b4f4ec06ba4ceaa49d675b4ba80716f3bc6976b1fbf9c8bf1f3e3a4dc1cd83ef9cf816667fb94f1e923ff63fef072e6a19321e4812f96cb0ffa864da50ad74deb76917a336f31dce03ed5f0303aad5e6a83634f9fcc371096f8288b8f02ddded5ff1bb9d49331e4a84dbe1543164438fde9ad71dab024779dcdde0b6602b5ae0a6265c14b94edd83b37403f4b78fcd2ed555b596402c28ee81d87a909c4e8722b30c71ecdd861b05f61f8b1231795c76adba2fdefa451b283a5d527955b9f3de1b9828e7b2e74123dd47062ddcc09b05e7fa13cb2212a6fdbc65d7e852cec463ec6fd929f5b8483cf3052113b13dac91b69f49d1b7d1aec01c4a68e41ce1570101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff071f0104455a6361736830623963346565663862376363343137656535303031653335303039383462366665613335363833613763616331343161303433633432303634383335643334ffffffff010000000000000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000";
let origin = origin.from_hex().unwrap();
let genesis: chain::Block = serialization::deserialize_with_flags(&origin as &[u8], serialization::DESERIALIZE_ZCASH).unwrap();
println!("=== ZCash genesis hash: {:?}", genesis.hash());
genesis
},
(&ConsensusFork::ZCash, Network::Testnet) =>
"".into(),
(&ConsensusFork::ZCash, Network::Regtest) | (&ConsensusFork::ZCash, Network::Unitest) =>
"".into(),
(_, Network::Mainnet) | (_, Network::Other(_)) => "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000".into(),
(_, Network::Testnet) => "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff001d1aa4ae180101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000".into(),
(_, Network::Regtest) | (_, Network::Unitest) => "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff7f20020000000101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000".into(),
} }
} }
pub fn default_verification_edge(&self) -> H256 { pub fn default_verification_edge(&self, fork: &ConsensusFork) -> H256 {
match *self { match *self {
Network::Mainnet => H256::from_reversed_str("0000000000000000030abc968e1bd635736e880b946085c93152969b9a81a6e2"), Network::Mainnet => H256::from_reversed_str("0000000000000000030abc968e1bd635736e880b946085c93152969b9a81a6e2"),
Network::Testnet => H256::from_reversed_str("000000000871ee6842d3648317ccc8a435eb8cc3c2429aee94faff9ba26b05a0"), Network::Testnet => H256::from_reversed_str("000000000871ee6842d3648317ccc8a435eb8cc3c2429aee94faff9ba26b05a0"),
_ => self.genesis_block().hash(), _ => self.genesis_block(fork).hash(),
} }
} }
} }
@ -118,18 +154,18 @@ mod tests {
#[test] #[test]
fn test_network_max_bits() { fn test_network_max_bits() {
assert_eq!(Network::Mainnet.max_bits(), *MAX_BITS_MAINNET); assert_eq!(Network::Mainnet.max_bits(&ConsensusFork::BitcoinCore), *MAX_BITS_MAINNET);
assert_eq!(Network::Testnet.max_bits(), *MAX_BITS_TESTNET); assert_eq!(Network::Testnet.max_bits(&ConsensusFork::BitcoinCore), *MAX_BITS_TESTNET);
assert_eq!(Network::Regtest.max_bits(), *MAX_BITS_REGTEST); assert_eq!(Network::Regtest.max_bits(&ConsensusFork::BitcoinCore), *MAX_BITS_REGTEST);
assert_eq!(Network::Unitest.max_bits(), Compact::max_value().into()); assert_eq!(Network::Unitest.max_bits(&ConsensusFork::BitcoinCore), Compact::max_value().into());
} }
#[test] #[test]
fn test_network_port() { fn test_network_port() {
assert_eq!(Network::Mainnet.port(), 8333); assert_eq!(Network::Mainnet.port(&ConsensusFork::BitcoinCore), 8333);
assert_eq!(Network::Testnet.port(), 18333); assert_eq!(Network::Testnet.port(&ConsensusFork::BitcoinCore), 18333);
assert_eq!(Network::Regtest.port(), 18444); assert_eq!(Network::Regtest.port(&ConsensusFork::BitcoinCore), 18444);
assert_eq!(Network::Unitest.port(), 18444); assert_eq!(Network::Unitest.port(&ConsensusFork::BitcoinCore), 18444);
} }
#[test] #[test]

View File

@ -23,4 +23,6 @@ pub struct Config {
pub preferable_services: Services, pub preferable_services: Services,
/// Internet protocol. /// Internet protocol.
pub internet_protocol: InternetProtocol, pub internet_protocol: InternetProtocol,
/// Serialization flags.
pub serialization_flags: u32,
} }

View File

@ -6,26 +6,28 @@ use message::types::{Version, Verack};
use network::Magic; use network::Magic;
use io::{write_message, WriteMessage, ReadMessage, read_message}; use io::{write_message, WriteMessage, ReadMessage, read_message};
pub fn handshake<A>(a: A, magic: Magic, version: Version, min_version: u32) -> Handshake<A> where A: AsyncWrite + AsyncRead { pub fn handshake<A>(a: A, flags: u32, magic: Magic, version: Version, min_version: u32) -> Handshake<A> where A: AsyncWrite + AsyncRead {
Handshake { Handshake {
version: version.version(), version: version.version(),
nonce: version.nonce(), nonce: version.nonce(),
state: HandshakeState::SendVersion(write_message(a, version_message(magic, version))), state: HandshakeState::SendVersion(write_message(a, version_message(magic, version))),
magic: magic, magic: magic,
min_version: min_version, min_version: min_version,
flags: flags,
} }
} }
pub fn accept_handshake<A>(a: A, magic: Magic, version: Version, min_version: u32) -> AcceptHandshake<A> where A: AsyncWrite + AsyncRead { pub fn accept_handshake<A>(a: A, flags: u32, magic: Magic, version: Version, min_version: u32) -> AcceptHandshake<A> where A: AsyncWrite + AsyncRead {
AcceptHandshake { AcceptHandshake {
version: version.version(), version: version.version(),
nonce: version.nonce(), nonce: version.nonce(),
state: AcceptHandshakeState::ReceiveVersion { state: AcceptHandshakeState::ReceiveVersion {
local_version: Some(version), local_version: Some(version),
future: read_message(a, magic, 0), future: read_message(a, flags, magic, 0),
}, },
magic: magic, magic: magic,
min_version: min_version, min_version: min_version,
flags: flags,
} }
} }
@ -81,6 +83,7 @@ pub struct Handshake<A> {
version: u32, version: u32,
nonce: Option<u64>, nonce: Option<u64>,
min_version: u32, min_version: u32,
flags: u32,
} }
pub struct AcceptHandshake<A> { pub struct AcceptHandshake<A> {
@ -89,6 +92,7 @@ pub struct AcceptHandshake<A> {
version: u32, version: u32,
nonce: Option<u64>, nonce: Option<u64>,
min_version: u32, min_version: u32,
flags: u32,
} }
impl<A> Future for Handshake<A> where A: AsyncRead + AsyncWrite { impl<A> Future for Handshake<A> where A: AsyncRead + AsyncWrite {
@ -100,20 +104,24 @@ impl<A> Future for Handshake<A> where A: AsyncRead + AsyncWrite {
let next_state = match self.state { let next_state = match self.state {
HandshakeState::SendVersion(ref mut future) => { HandshakeState::SendVersion(ref mut future) => {
let (stream, _) = try_ready!(future.poll()); let (stream, _) = try_ready!(future.poll());
HandshakeState::ReceiveVersion(read_message(stream, self.magic, 0)) println!("=== 1");
HandshakeState::ReceiveVersion(read_message(stream, self.flags, self.magic, 0))
}, },
HandshakeState::ReceiveVersion(ref mut future) => { HandshakeState::ReceiveVersion(ref mut future) => {
let (stream, version) = try_ready!(future.poll()); let (stream, version) = try_ready!(future.poll());
println!("=== 2: {:?}", version);
let version = match version { let version = match version {
Ok(version) => version, Ok(version) => version,
Err(err) => return Ok((stream, Err(err.into())).into()), Err(err) => return Ok((stream, Err(err.into())).into()),
}; };
if version.version() < self.min_version { if version.version() < self.min_version {
println!("=== 2.1: {} < {}", version.version(), self.min_version);
return Ok((stream, Err(Error::InvalidVersion)).into()); return Ok((stream, Err(Error::InvalidVersion)).into());
} }
if let (Some(self_nonce), Some(nonce)) = (self.nonce, version.nonce()) { if let (Some(self_nonce), Some(nonce)) = (self.nonce, version.nonce()) {
if self_nonce == nonce { if self_nonce == nonce {
println!("=== 2.2: {} == {}", self_nonce, nonce);
return Ok((stream, Err(Error::InvalidVersion)).into()); return Ok((stream, Err(Error::InvalidVersion)).into());
} }
} }
@ -125,16 +133,17 @@ impl<A> Future for Handshake<A> where A: AsyncRead + AsyncWrite {
}, },
HandshakeState::SendVerack { ref mut version, ref mut future } => { HandshakeState::SendVerack { ref mut version, ref mut future } => {
let (stream, _) = try_ready!(future.poll()); let (stream, _) = try_ready!(future.poll());
println!("=== 3");
let version = version.take().expect("verack must be preceded by version"); let version = version.take().expect("verack must be preceded by version");
HandshakeState::ReceiveVerack { HandshakeState::ReceiveVerack {
version: Some(version), version: Some(version),
future: read_message(stream, self.magic, 0), future: read_message(stream, self.flags, self.magic, 0),
} }
}, },
HandshakeState::ReceiveVerack { ref mut version, ref mut future } => { HandshakeState::ReceiveVerack { ref mut version, ref mut future } => {
let (stream, _verack) = try_ready!(future.poll()); let (stream, _verack) = try_ready!(future.poll());
println!("=== 4");
let version = version.take().expect("verack must be preceded by version"); let version = version.take().expect("verack must be preceded by version");
let result = HandshakeResult { let result = HandshakeResult {
@ -310,7 +319,7 @@ mod tests {
write: Bytes::default(), write: Bytes::default(),
}; };
let hs = handshake(test_io, magic, local_version, 0).wait().unwrap(); let hs = handshake(test_io, 0, magic, local_version, 0).wait().unwrap();
assert_eq!(hs.0.write, expected_stream.out()); assert_eq!(hs.0.write, expected_stream.out());
assert_eq!(hs.1.unwrap(), expected); assert_eq!(hs.1.unwrap(), expected);
} }
@ -339,7 +348,7 @@ mod tests {
expected_stream.append_slice(Message::new(magic, version, &local_version).unwrap().as_ref()); expected_stream.append_slice(Message::new(magic, version, &local_version).unwrap().as_ref());
expected_stream.append_slice(Message::new(magic, version, &Verack).unwrap().as_ref()); expected_stream.append_slice(Message::new(magic, version, &Verack).unwrap().as_ref());
let hs = accept_handshake(test_io, magic, local_version, 0).wait().unwrap(); let hs = accept_handshake(test_io, 0, magic, local_version, 0).wait().unwrap();
assert_eq!(hs.0.write, expected_stream.out()); assert_eq!(hs.0.write, expected_stream.out());
assert_eq!(hs.1.unwrap(), expected); assert_eq!(hs.1.unwrap(), expected);
} }
@ -361,7 +370,7 @@ mod tests {
let expected = Error::InvalidVersion; let expected = Error::InvalidVersion;
let hs = handshake(test_io, magic, local_version, 0).wait().unwrap(); let hs = handshake(test_io, 0, magic, local_version, 0).wait().unwrap();
assert_eq!(hs.1.unwrap_err(), expected); assert_eq!(hs.1.unwrap_err(), expected);
} }
@ -382,7 +391,7 @@ mod tests {
let expected = Error::InvalidVersion; let expected = Error::InvalidVersion;
let hs = accept_handshake(test_io, magic, local_version, 0).wait().unwrap(); let hs = accept_handshake(test_io, 0, magic, local_version, 0).wait().unwrap();
assert_eq!(hs.1.unwrap_err(), expected); assert_eq!(hs.1.unwrap_err(), expected);
} }
@ -404,7 +413,7 @@ mod tests {
let expected = Error::InvalidMagic; let expected = Error::InvalidMagic;
let hs = accept_handshake(test_io, magic1, local_version, 0).wait().unwrap(); let hs = accept_handshake(test_io, 0, magic1, local_version, 0).wait().unwrap();
assert_eq!(hs.1.unwrap_err(), expected); assert_eq!(hs.1.unwrap_err(), expected);
} }
} }

View File

@ -8,9 +8,9 @@ use message::{Error, MessageHeader, MessageResult, Command};
use bytes::Bytes; use bytes::Bytes;
use io::{read_header, ReadHeader}; use io::{read_header, ReadHeader};
pub fn read_any_message<A>(a: A, magic: Magic) -> ReadAnyMessage<A> where A: AsyncRead { pub fn read_any_message<A>(a: A, flags: u32, magic: Magic) -> ReadAnyMessage<A> where A: AsyncRead {
ReadAnyMessage { ReadAnyMessage {
state: ReadAnyMessageState::ReadHeader(read_header(a, magic)), state: ReadAnyMessageState::ReadHeader(read_header(a, flags, magic)),
} }
} }
@ -74,20 +74,20 @@ mod tests {
let nonce = "5845303b6da97786".into(); let nonce = "5845303b6da97786".into();
let expected = (name, nonce); let expected = (name, nonce);
assert_eq!(read_any_message(raw.as_ref(), Network::Mainnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap(), Ok(expected)); assert_eq!(read_any_message(raw.as_ref(), 0, Network::Mainnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap(), Ok(expected));
assert_eq!(read_any_message(raw.as_ref(), Network::Testnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap(), Err(Error::InvalidMagic)); assert_eq!(read_any_message(raw.as_ref(), 0, Network::Testnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap(), Err(Error::InvalidMagic));
} }
#[test] #[test]
fn test_read_too_short_any_message() { fn test_read_too_short_any_message() {
let raw: Bytes = "f9beb4d970696e6700000000000000000800000083c00c765845303b6da977".into(); let raw: Bytes = "f9beb4d970696e6700000000000000000800000083c00c765845303b6da977".into();
assert!(read_any_message(raw.as_ref(), Network::Mainnet.magic(&ConsensusFork::BitcoinCore)).wait().is_err()); assert!(read_any_message(raw.as_ref(), 0, Network::Mainnet.magic(&ConsensusFork::BitcoinCore)).wait().is_err());
} }
#[test] #[test]
fn test_read_any_message_with_invalid_checksum() { fn test_read_any_message_with_invalid_checksum() {
let raw: Bytes = "f9beb4d970696e6700000000000000000800000083c01c765845303b6da97786".into(); let raw: Bytes = "f9beb4d970696e6700000000000000000800000083c01c765845303b6da97786".into();
assert_eq!(read_any_message(raw.as_ref(), Network::Mainnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap(), Err(Error::InvalidChecksum)); assert_eq!(read_any_message(raw.as_ref(), 0, Network::Mainnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap(), Err(Error::InvalidChecksum));
} }
} }

View File

@ -5,15 +5,17 @@ use tokio_io::io::{ReadExact, read_exact};
use message::{MessageHeader, MessageResult}; use message::{MessageHeader, MessageResult};
use network::Magic; use network::Magic;
pub fn read_header<A>(a: A, magic: Magic) -> ReadHeader<A> where A: AsyncRead { pub fn read_header<A>(a: A, flags: u32, magic: Magic) -> ReadHeader<A> where A: AsyncRead {
ReadHeader { ReadHeader {
reader: read_exact(a, [0u8; 24]), reader: read_exact(a, [0u8; 24]),
magic: magic, magic: magic,
flags: flags,
} }
} }
pub struct ReadHeader<A> { pub struct ReadHeader<A> {
reader: ReadExact<A, [u8; 24]>, reader: ReadExact<A, [u8; 24]>,
flags: u32,
magic: Magic, magic: Magic,
} }
@ -23,7 +25,7 @@ impl<A> Future for ReadHeader<A> where A: AsyncRead {
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let (read, data) = try_ready!(self.reader.poll()); let (read, data) = try_ready!(self.reader.poll());
let header = MessageHeader::deserialize(&data, self.magic); let header = MessageHeader::deserialize(&data, self.flags, self.magic);
Ok(Async::Ready((read, header))) Ok(Async::Ready((read, header)))
} }
} }
@ -46,19 +48,19 @@ mod tests {
checksum: "ed52399b".into(), checksum: "ed52399b".into(),
}; };
assert_eq!(read_header(raw.as_ref(), Network::Mainnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap().1, Ok(expected)); assert_eq!(read_header(raw.as_ref(), 0, Network::Mainnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap().1, Ok(expected));
assert_eq!(read_header(raw.as_ref(), Network::Testnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap().1, Err(Error::InvalidMagic)); assert_eq!(read_header(raw.as_ref(), 0, Network::Testnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap().1, Err(Error::InvalidMagic));
} }
#[test] #[test]
fn test_read_header_with_invalid_magic() { fn test_read_header_with_invalid_magic() {
let raw: Bytes = "f9beb4d86164647200000000000000001f000000ed52399b".into(); let raw: Bytes = "f9beb4d86164647200000000000000001f000000ed52399b".into();
assert_eq!(read_header(raw.as_ref(), Network::Testnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap().1, Err(Error::InvalidMagic)); assert_eq!(read_header(raw.as_ref(), 0, Network::Testnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap().1, Err(Error::InvalidMagic));
} }
#[test] #[test]
fn test_read_too_short_header() { fn test_read_too_short_header() {
let raw: Bytes = "f9beb4d96164647200000000000000001f000000ed5239".into(); let raw: Bytes = "f9beb4d96164647200000000000000001f000000ed5239".into();
assert!(read_header(raw.as_ref(), Network::Mainnet.magic(&ConsensusFork::BitcoinCore)).wait().is_err()); assert!(read_header(raw.as_ref(), 0, Network::Mainnet.magic(&ConsensusFork::BitcoinCore)).wait().is_err());
} }
} }

View File

@ -6,14 +6,15 @@ use network::Magic;
use message::{MessageResult, Error, Payload}; use message::{MessageResult, Error, Payload};
use io::{read_header, ReadHeader, read_payload, ReadPayload}; use io::{read_header, ReadHeader, read_payload, ReadPayload};
pub fn read_message<M, A>(a: A, magic: Magic, version: u32) -> ReadMessage<M, A> pub fn read_message<M, A>(a: A, flags: u32, magic: Magic, version: u32) -> ReadMessage<M, A>
where A: AsyncRead, M: Payload { where A: AsyncRead, M: Payload {
ReadMessage { ReadMessage {
state: ReadMessageState::ReadHeader { state: ReadMessageState::ReadHeader {
version: version, version: version,
future: read_header(a, magic), future: read_header(a, flags, magic),
}, },
message_type: PhantomData flags: flags,
message_type: PhantomData,
} }
} }
@ -29,6 +30,7 @@ enum ReadMessageState<M, A> {
pub struct ReadMessage<M, A> { pub struct ReadMessage<M, A> {
state: ReadMessageState<M, A>, state: ReadMessageState<M, A>,
flags: u32,
message_type: PhantomData<M>, message_type: PhantomData<M>,
} }
@ -41,15 +43,18 @@ impl<M, A> Future for ReadMessage<M, A> where A: AsyncRead, M: Payload {
let next_state = match self.state { let next_state = match self.state {
ReadMessageState::ReadHeader { version, ref mut future } => { ReadMessageState::ReadHeader { version, ref mut future } => {
let (read, header) = try_ready!(future.poll()); let (read, header) = try_ready!(future.poll());
println!("=== 10: {:?}", header);
let header = match header { let header = match header {
Ok(header) => header, Ok(header) => header,
Err(err) => return Ok((read, Err(err)).into()), Err(err) => return Ok((read, Err(err)).into()),
}; };
let s: String = header.command.clone().into();
println!("=== 11: {}", s);
if header.command != M::command() { if header.command != M::command() {
return Ok((read, Err(Error::InvalidCommand)).into()); return Ok((read, Err(Error::InvalidCommand)).into());
} }
let future = read_payload( let future = read_payload(
read, version, header.len as usize, header.checksum, read, version, self.flags, header.len as usize, header.checksum,
); );
ReadMessageState::ReadPayload { ReadMessageState::ReadPayload {
future: future, future: future,
@ -78,21 +83,21 @@ mod tests {
fn test_read_message() { fn test_read_message() {
let raw: Bytes = "f9beb4d970696e6700000000000000000800000083c00c765845303b6da97786".into(); let raw: Bytes = "f9beb4d970696e6700000000000000000800000083c00c765845303b6da97786".into();
let ping = Ping::new(u64::from_str_radix("8677a96d3b304558", 16).unwrap()); let ping = Ping::new(u64::from_str_radix("8677a96d3b304558", 16).unwrap());
assert_eq!(read_message(raw.as_ref(), Network::Mainnet.magic(&ConsensusFork::BitcoinCore), 0).wait().unwrap().1, Ok(ping)); assert_eq!(read_message(raw.as_ref(), 0, Network::Mainnet.magic(&ConsensusFork::BitcoinCore), 0).wait().unwrap().1, Ok(ping));
assert_eq!(read_message::<Ping, _>(raw.as_ref(), Network::Testnet.magic(&ConsensusFork::BitcoinCore), 0).wait().unwrap().1, Err(Error::InvalidMagic)); assert_eq!(read_message::<Ping, _>(raw.as_ref(), 0, Network::Testnet.magic(&ConsensusFork::BitcoinCore), 0).wait().unwrap().1, Err(Error::InvalidMagic));
assert_eq!(read_message::<Pong, _>(raw.as_ref(), Network::Mainnet.magic(&ConsensusFork::BitcoinCore), 0).wait().unwrap().1, Err(Error::InvalidCommand)); assert_eq!(read_message::<Pong, _>(raw.as_ref(), 0, Network::Mainnet.magic(&ConsensusFork::BitcoinCore), 0).wait().unwrap().1, Err(Error::InvalidCommand));
} }
#[test] #[test]
fn test_read_too_short_message() { fn test_read_too_short_message() {
let raw: Bytes = "f9beb4d970696e6700000000000000000800000083c00c765845303b6da977".into(); let raw: Bytes = "f9beb4d970696e6700000000000000000800000083c00c765845303b6da977".into();
assert!(read_message::<Ping, _>(raw.as_ref(), Network::Mainnet.magic(&ConsensusFork::BitcoinCore), 0).wait().is_err()); assert!(read_message::<Ping, _>(raw.as_ref(), 0, Network::Mainnet.magic(&ConsensusFork::BitcoinCore), 0).wait().is_err());
} }
#[test] #[test]
fn test_read_message_with_invalid_checksum() { fn test_read_message_with_invalid_checksum() {
let raw: Bytes = "f9beb4d970696e6700000000000000000800000083c01c765845303b6da97786".into(); let raw: Bytes = "f9beb4d970696e6700000000000000000800000083c01c765845303b6da97786".into();
assert_eq!(read_message::<Ping, _>(raw.as_ref(), Network::Mainnet.magic(&ConsensusFork::BitcoinCore), 0).wait().unwrap().1, Err(Error::InvalidChecksum)); assert_eq!(read_message::<Ping, _>(raw.as_ref(), 0, Network::Mainnet.magic(&ConsensusFork::BitcoinCore), 0).wait().unwrap().1, Err(Error::InvalidChecksum));
} }
} }

View File

@ -8,11 +8,12 @@ use hash::H32;
use crypto::checksum; use crypto::checksum;
use message::{Error, MessageResult, Payload, deserialize_payload}; use message::{Error, MessageResult, Payload, deserialize_payload};
pub fn read_payload<M, A>(a: A, version: u32, len: usize, checksum: H32) -> ReadPayload<M, A> pub fn read_payload<M, A>(a: A, version: u32, flags: u32, len: usize, checksum: H32) -> ReadPayload<M, A>
where A: AsyncRead, M: Payload { where A: AsyncRead, M: Payload {
ReadPayload { ReadPayload {
reader: read_exact(a, Bytes::new_with_len(len)), reader: read_exact(a, Bytes::new_with_len(len)),
version: version, version: version,
flags: flags,
checksum: checksum, checksum: checksum,
payload_type: PhantomData, payload_type: PhantomData,
} }
@ -21,6 +22,7 @@ pub fn read_payload<M, A>(a: A, version: u32, len: usize, checksum: H32) -> Read
pub struct ReadPayload<M, A> { pub struct ReadPayload<M, A> {
reader: ReadExact<A, Bytes>, reader: ReadExact<A, Bytes>,
version: u32, version: u32,
flags: u32,
checksum: H32, checksum: H32,
payload_type: PhantomData<M>, payload_type: PhantomData<M>,
} }
@ -34,7 +36,7 @@ impl<M, A> Future for ReadPayload<M, A> where A: AsyncRead, M: Payload {
if checksum(&data) != self.checksum { if checksum(&data) != self.checksum {
return Ok((read, Err(Error::InvalidChecksum)).into()); return Ok((read, Err(Error::InvalidChecksum)).into());
} }
let payload = deserialize_payload(&data, self.version); let payload = deserialize_payload(&data, self.version, self.flags);
Ok((read, payload).into()) Ok((read, payload).into())
} }
} }
@ -51,18 +53,18 @@ mod tests {
fn test_read_payload() { fn test_read_payload() {
let raw: Bytes = "5845303b6da97786".into(); let raw: Bytes = "5845303b6da97786".into();
let ping = Ping::new(u64::from_str_radix("8677a96d3b304558", 16).unwrap()); let ping = Ping::new(u64::from_str_radix("8677a96d3b304558", 16).unwrap());
assert_eq!(read_payload(raw.as_ref(), 0, 8, "83c00c76".into()).wait().unwrap().1, Ok(ping)); assert_eq!(read_payload(raw.as_ref(), 0, 0, 8, "83c00c76".into()).wait().unwrap().1, Ok(ping));
} }
#[test] #[test]
fn test_read_payload_with_invalid_checksum() { fn test_read_payload_with_invalid_checksum() {
let raw: Bytes = "5845303b6da97786".into(); let raw: Bytes = "5845303b6da97786".into();
assert_eq!(read_payload::<Ping, _>(raw.as_ref(), 0, 8, "83c00c75".into()).wait().unwrap().1, Err(Error::InvalidChecksum)); assert_eq!(read_payload::<Ping, _>(raw.as_ref(), 0, 0, 8, "83c00c75".into()).wait().unwrap().1, Err(Error::InvalidChecksum));
} }
#[test] #[test]
fn test_read_too_short_payload() { fn test_read_too_short_payload() {
let raw: Bytes = "5845303b6da977".into(); let raw: Bytes = "5845303b6da977".into();
assert!(read_payload::<Ping, _>(raw.as_ref(), 0, 8, "83c00c76".into()).wait().is_err()); assert!(read_payload::<Ping, _>(raw.as_ref(), 0, 0, 8, "83c00c76".into()).wait().is_err());
} }
} }

View File

@ -10,7 +10,7 @@ use net::{Config, Connection};
pub fn accept_connection(stream: TcpStream, handle: &Handle, config: &Config, address: net::SocketAddr) -> Deadline<AcceptConnection> { pub fn accept_connection(stream: TcpStream, handle: &Handle, config: &Config, address: net::SocketAddr) -> Deadline<AcceptConnection> {
let accept = AcceptConnection { let accept = AcceptConnection {
handshake: accept_handshake(stream, config.magic, config.version(&address), config.protocol_minimum), handshake: accept_handshake(stream, config.serialization_flags, config.magic, config.version(&address), config.protocol_minimum),
magic: config.magic, magic: config.magic,
address: address, address: address,
}; };

View File

@ -23,7 +23,7 @@ impl Channel {
} }
pub fn read_message(&self) -> ReadAnyMessage<SharedTcpStream> { pub fn read_message(&self) -> ReadAnyMessage<SharedTcpStream> {
read_any_message(self.stream.clone(), self.peer_info.magic) read_any_message(self.stream.clone(), self.peer_info.flags, self.peer_info.magic)
} }
pub fn shutdown(&self) { pub fn shutdown(&self) {

View File

@ -15,6 +15,7 @@ pub struct Config {
pub user_agent: String, pub user_agent: String,
pub start_height: i32, pub start_height: i32,
pub relay: bool, pub relay: bool,
pub serialization_flags: u32,
} }
impl Config { impl Config {

View File

@ -19,6 +19,7 @@ pub fn connect(address: &SocketAddr, handle: &Handle, config: &Config) -> Deadli
magic: config.magic, magic: config.magic,
address: *address, address: *address,
protocol_minimum: config.protocol_minimum, protocol_minimum: config.protocol_minimum,
flags: config.serialization_flags,
}; };
deadline(Duration::new(5, 0), handle, connect).expect("Failed to create timeout") deadline(Duration::new(5, 0), handle, connect).expect("Failed to create timeout")
@ -38,6 +39,7 @@ pub struct Connect {
magic: Magic, magic: Magic,
address: SocketAddr, address: SocketAddr,
protocol_minimum: u32, protocol_minimum: u32,
flags: u32,
} }
impl Future for Connect { impl Future for Connect {
@ -49,7 +51,7 @@ impl Future for Connect {
ConnectState::TcpConnect { ref mut future, ref mut version } => { ConnectState::TcpConnect { ref mut future, ref mut version } => {
let stream = try_ready!(future.poll()); let stream = try_ready!(future.poll());
let version = version.take().expect("state TcpConnect must have version"); let version = version.take().expect("state TcpConnect must have version");
let handshake = handshake(stream, self.magic, version, self.protocol_minimum); let handshake = handshake(stream, self.flags, self.magic, version, self.protocol_minimum);
(ConnectState::Handshake(handshake), Async::NotReady) (ConnectState::Handshake(handshake), Async::NotReady)
}, },
ConnectState::Handshake(ref mut future) => { ConnectState::Handshake(ref mut future) => {

View File

@ -58,6 +58,7 @@ impl Connections {
version: connection.version, version: connection.version,
version_message: connection.version_message, version_message: connection.version_message,
magic: connection.magic, magic: connection.magic,
flags: context.serialization_flags(),
}; };
let session = T::new_session(context, peer_info.clone(), SYNCHRONOUS_RESPONSES); let session = T::new_session(context, peer_info.clone(), SYNCHRONOUS_RESPONSES);

View File

@ -402,6 +402,10 @@ impl Context {
pub fn nodes(&self) -> Vec<Node> { pub fn nodes(&self) -> Vec<Node> {
self.node_table.read().nodes() self.node_table.read().nodes()
} }
pub fn serialization_flags(&self) -> u32 {
self.config.serialization_flags
}
} }
pub struct P2P { pub struct P2P {

View File

@ -34,12 +34,12 @@ impl Protocol for AddrProtocol {
// normal nodes send addr message only after they receive getaddr message // normal nodes send addr message only after they receive getaddr message
// meanwhile seednodes, surprisingly, send addr message even before they are asked for it // meanwhile seednodes, surprisingly, send addr message even before they are asked for it
if command == &GetAddr::command() { if command == &GetAddr::command() {
let _: GetAddr = try!(deserialize_payload(payload, self.context.info().version)); let _: GetAddr = try!(deserialize_payload(payload, self.context.info().version, self.context.info().flags));
let entries = self.context.global().node_table_entries().into_iter().map(Into::into).collect(); let entries = self.context.global().node_table_entries().into_iter().map(Into::into).collect();
let addr = Addr::new(entries); let addr = Addr::new(entries);
self.context.send_response_inline(&addr); self.context.send_response_inline(&addr);
} else if command == &Addr::command() { } else if command == &Addr::command() {
let addr: Addr = try!(deserialize_payload(payload, self.context.info().version)); let addr: Addr = try!(deserialize_payload(payload, self.context.info().version, self.context.info().flags));
match addr { match addr {
Addr::V0(_) => { Addr::V0(_) => {
unreachable!("This version of protocol is not supported!"); unreachable!("This version of protocol is not supported!");

View File

@ -78,11 +78,11 @@ impl Protocol for PingProtocol {
self.state = State::WaitingTimeout(time::precise_time_s()); self.state = State::WaitingTimeout(time::precise_time_s());
if command == &Ping::command() { if command == &Ping::command() {
let ping: Ping = try!(deserialize_payload(payload, self.context.info().version)); let ping: Ping = try!(deserialize_payload(payload, self.context.info().version, self.context.info().flags));
let pong = Pong::new(ping.nonce); let pong = Pong::new(ping.nonce);
self.context.send_response_inline(&pong); self.context.send_response_inline(&pong);
} else if command == &Pong::command() { } else if command == &Pong::command() {
let pong: Pong = try!(deserialize_payload(payload, self.context.info().version)); let pong: Pong = try!(deserialize_payload(payload, self.context.info().version, self.context.info().flags));
if Some(pong.nonce) != self.last_ping_nonce.take() { if Some(pong.nonce) != self.last_ping_nonce.take() {
return Err(Error::InvalidCommand) return Err(Error::InvalidCommand)
} }

View File

@ -202,82 +202,83 @@ impl Protocol for SyncProtocol {
fn on_message(&mut self, command: &Command, payload: &Bytes) -> Result<(), Error> { fn on_message(&mut self, command: &Command, payload: &Bytes) -> Result<(), Error> {
let version = self.context.info().version; let version = self.context.info().version;
let flags = self.context.info().flags;
if command == &types::Inv::command() { if command == &types::Inv::command() {
let message: types::Inv = try!(deserialize_payload(payload, version)); let message: types::Inv = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_inventory(message); self.inbound_connection.on_inventory(message);
} }
else if command == &types::GetData::command() { else if command == &types::GetData::command() {
let message: types::GetData = try!(deserialize_payload(payload, version)); let message: types::GetData = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_getdata(message); self.inbound_connection.on_getdata(message);
} }
else if command == &types::GetBlocks::command() { else if command == &types::GetBlocks::command() {
let message: types::GetBlocks = try!(deserialize_payload(payload, version)); let message: types::GetBlocks = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_getblocks(message); self.inbound_connection.on_getblocks(message);
} }
else if command == &types::GetHeaders::command() { else if command == &types::GetHeaders::command() {
let message: types::GetHeaders = try!(deserialize_payload(payload, version)); let message: types::GetHeaders = try!(deserialize_payload(payload, version, flags));
let id = self.context.declare_response(); let id = self.context.declare_response();
trace!("declared response {} for request: {}", id, types::GetHeaders::command()); trace!("declared response {} for request: {}", id, types::GetHeaders::command());
self.inbound_connection.on_getheaders(message, id); self.inbound_connection.on_getheaders(message, id);
} }
else if command == &types::Tx::command() { else if command == &types::Tx::command() {
let message: types::Tx = try!(deserialize_payload(payload, version)); let message: types::Tx = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_transaction(message); self.inbound_connection.on_transaction(message);
} }
else if command == &types::Block::command() { else if command == &types::Block::command() {
let message: types::Block = try!(deserialize_payload(payload, version)); let message: types::Block = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_block(message); self.inbound_connection.on_block(message);
} }
else if command == &types::MemPool::command() { else if command == &types::MemPool::command() {
let message: types::MemPool = try!(deserialize_payload(payload, version)); let message: types::MemPool = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_mempool(message); self.inbound_connection.on_mempool(message);
} }
else if command == &types::Headers::command() { else if command == &types::Headers::command() {
let message: types::Headers = try!(deserialize_payload(payload, version)); let message: types::Headers = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_headers(message); self.inbound_connection.on_headers(message);
} }
else if command == &types::FilterLoad::command() { else if command == &types::FilterLoad::command() {
let message: types::FilterLoad = try!(deserialize_payload(payload, version)); let message: types::FilterLoad = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_filterload(message); self.inbound_connection.on_filterload(message);
} }
else if command == &types::FilterAdd::command() { else if command == &types::FilterAdd::command() {
let message: types::FilterAdd = try!(deserialize_payload(payload, version)); let message: types::FilterAdd = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_filteradd(message); self.inbound_connection.on_filteradd(message);
} }
else if command == &types::FilterClear::command() { else if command == &types::FilterClear::command() {
let message: types::FilterClear = try!(deserialize_payload(payload, version)); let message: types::FilterClear = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_filterclear(message); self.inbound_connection.on_filterclear(message);
} }
else if command == &types::MerkleBlock::command() { else if command == &types::MerkleBlock::command() {
let message: types::MerkleBlock = try!(deserialize_payload(payload, version)); let message: types::MerkleBlock = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_merkleblock(message); self.inbound_connection.on_merkleblock(message);
} }
else if command == &types::SendHeaders::command() { else if command == &types::SendHeaders::command() {
let message: types::SendHeaders = try!(deserialize_payload(payload, version)); let message: types::SendHeaders = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_sendheaders(message); self.inbound_connection.on_sendheaders(message);
} }
else if command == &types::FeeFilter::command() { else if command == &types::FeeFilter::command() {
let message: types::FeeFilter = try!(deserialize_payload(payload, version)); let message: types::FeeFilter = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_feefilter(message); self.inbound_connection.on_feefilter(message);
} }
else if command == &types::SendCompact::command() { else if command == &types::SendCompact::command() {
let message: types::SendCompact = try!(deserialize_payload(payload, version)); let message: types::SendCompact = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_send_compact(message); self.inbound_connection.on_send_compact(message);
} }
else if command == &types::CompactBlock::command() { else if command == &types::CompactBlock::command() {
let message: types::CompactBlock = try!(deserialize_payload(payload, version)); let message: types::CompactBlock = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_compact_block(message); self.inbound_connection.on_compact_block(message);
} }
else if command == &types::GetBlockTxn::command() { else if command == &types::GetBlockTxn::command() {
let message: types::GetBlockTxn = try!(deserialize_payload(payload, version)); let message: types::GetBlockTxn = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_get_block_txn(message); self.inbound_connection.on_get_block_txn(message);
} }
else if command == &types::BlockTxn::command() { else if command == &types::BlockTxn::command() {
let message: types::BlockTxn = try!(deserialize_payload(payload, version)); let message: types::BlockTxn = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_block_txn(message); self.inbound_connection.on_block_txn(message);
} }
else if command == &types::NotFound::command() { else if command == &types::NotFound::command() {
let message: types::NotFound = try!(deserialize_payload(payload, version)); let message: types::NotFound = try!(deserialize_payload(payload, version, flags));
self.inbound_connection.on_notfound(message); self.inbound_connection.on_notfound(message);
} }
Ok(()) Ok(())

View File

@ -19,5 +19,6 @@ pub struct PeerInfo {
pub version: u32, pub version: u32,
pub version_message: types::Version, pub version_message: types::Version,
pub magic: Magic, pub magic: Magic,
pub flags: u32,
} }

View File

@ -15,6 +15,9 @@ args:
- bch: - bch:
long: bch long: bch
help: Use Bitcoin Cash verification rules (BCH). help: Use Bitcoin Cash verification rules (BCH).
- zcash:
long: zcash
help: Use ZCash verification rules (ZCH).
- connect: - connect:
short: c short: c
long: connect long: connect

View File

@ -18,7 +18,7 @@ pub fn rollback(cfg: Config, matches: &ArgMatches) -> Result<(), String> {
}; };
let required_block_hash = cfg.db.block_header(block_ref.clone()).ok_or(format!("Block {:?} is unknown", block_ref))?.hash(); let required_block_hash = cfg.db.block_header(block_ref.clone()).ok_or(format!("Block {:?} is unknown", block_ref))?.hash();
let genesis_hash = cfg.network.genesis_block().hash(); let genesis_hash = cfg.network.genesis_block(&cfg.consensus.fork).hash();
let mut best_block_hash = cfg.db.best_block().hash; let mut best_block_hash = cfg.db.best_block().hash;
debug_assert!(best_block_hash != H256::default()); // genesis inserted in init_db debug_assert!(best_block_hash != H256::default()); // genesis inserted in init_db

View File

@ -4,9 +4,10 @@ use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver}; use std::sync::mpsc::{channel, Sender, Receiver};
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use sync::{create_sync_peers, create_local_sync_node, create_sync_connection_factory, SyncListener}; use sync::{create_sync_peers, create_local_sync_node, create_sync_connection_factory, SyncListener};
use network::ConsensusFork;
use primitives::hash::H256; use primitives::hash::H256;
use util::{init_db, node_table_path}; use util::{init_db, node_table_path};
use {config, p2p, PROTOCOL_VERSION, PROTOCOL_MINIMUM}; use {config, p2p, PROTOCOL_VERSION, PROTOCOL_MINIMUM, ZCASH_PROTOCOL_VERSION, ZCASH_PROTOCOL_MINIMUM};
use super::super::rpc; use super::super::rpc;
enum BlockNotifierTask { enum BlockNotifierTask {
@ -88,25 +89,39 @@ pub fn start(cfg: config::Config) -> Result<(), String> {
let nodes_path = node_table_path(&cfg); let nodes_path = node_table_path(&cfg);
let SERIALIZE_ZCASH = 0x80000000; // TODO
let serialization_flags = match cfg.consensus.fork {
ConsensusFork::ZCash => SERIALIZE_ZCASH,
_ => 0,
};
let p2p_cfg = p2p::Config { let p2p_cfg = p2p::Config {
threads: cfg.p2p_threads, threads: cfg.p2p_threads,
inbound_connections: cfg.inbound_connections, inbound_connections: cfg.inbound_connections,
outbound_connections: cfg.outbound_connections, outbound_connections: cfg.outbound_connections,
connection: p2p::NetConfig { connection: p2p::NetConfig {
protocol_version: PROTOCOL_VERSION, protocol_version: match &cfg.consensus.fork {
protocol_minimum: PROTOCOL_MINIMUM, &ConsensusFork::ZCash => ZCASH_PROTOCOL_VERSION,
_ => PROTOCOL_VERSION,
},
protocol_minimum: match &cfg.consensus.fork {
&ConsensusFork::ZCash => ZCASH_PROTOCOL_MINIMUM,
_ => PROTOCOL_MINIMUM,
},
magic: cfg.consensus.magic(), magic: cfg.consensus.magic(),
local_address: SocketAddr::new("127.0.0.1".parse().unwrap(), cfg.port), local_address: SocketAddr::new("127.0.0.1".parse().unwrap(), cfg.port),
services: cfg.services, services: cfg.services,
user_agent: cfg.user_agent, user_agent: cfg.user_agent,
start_height: 0, start_height: 0,
relay: true, relay: true,
serialization_flags: serialization_flags,
}, },
peers: cfg.connect.map_or_else(|| vec![], |x| vec![x]), peers: cfg.connect.map_or_else(|| vec![], |x| vec![x]),
seeds: cfg.seednodes, seeds: cfg.seednodes,
node_table_path: nodes_path, node_table_path: nodes_path,
preferable_services: cfg.services, preferable_services: cfg.services,
internet_protocol: cfg.internet_protocol, internet_protocol: cfg.internet_protocol,
serialization_flags: serialization_flags,
}; };
let sync_peers = create_sync_peers(); let sync_peers = create_sync_peers();

View File

@ -4,7 +4,8 @@ use storage;
use message::Services; use message::Services;
use network::{Network, ConsensusParams, ConsensusFork, BitcoinCashConsensusParams}; use network::{Network, ConsensusParams, ConsensusFork, BitcoinCashConsensusParams};
use p2p::InternetProtocol; use p2p::InternetProtocol;
use seednodes::{mainnet_seednodes, testnet_seednodes, bitcoin_cash_seednodes, bitcoin_cash_testnet_seednodes}; use seednodes::{mainnet_seednodes, testnet_seednodes, bitcoin_cash_seednodes,
bitcoin_cash_testnet_seednodes, zcash_seednodes};
use rpc_apis::ApiSet; use rpc_apis::ApiSet;
use {USER_AGENT, REGTEST_USER_AGENT}; use {USER_AGENT, REGTEST_USER_AGENT};
use primitives::hash::H256; use primitives::hash::H256;
@ -74,7 +75,7 @@ pub fn parse(matches: &clap::ArgMatches) -> Result<Config, String> {
let user_agent_suffix = match consensus.fork { let user_agent_suffix = match consensus.fork {
ConsensusFork::BitcoinCore => "", ConsensusFork::BitcoinCore => "",
ConsensusFork::BitcoinCash(_) => "/UAHF", ConsensusFork::BitcoinCash(_) => "/UAHF",
ConsensusFork::ZCash => "/ZCash", ConsensusFork::ZCash => "",
}; };
let user_agent = match network { let user_agent = match network {
Network::Testnet | Network::Mainnet | Network::Unitest | Network::Other(_) => format!("{}{}", USER_AGENT, user_agent_suffix), Network::Testnet | Network::Mainnet | Network::Unitest | Network::Other(_) => format!("{}{}", USER_AGENT, user_agent_suffix),
@ -83,13 +84,13 @@ pub fn parse(matches: &clap::ArgMatches) -> Result<Config, String> {
let port = match matches.value_of("port") { let port = match matches.value_of("port") {
Some(port) => port.parse().map_err(|_| "Invalid port".to_owned())?, Some(port) => port.parse().map_err(|_| "Invalid port".to_owned())?,
None => network.port(), None => network.port(&consensus.fork),
}; };
let connect = match matches.value_of("connect") { let connect = match matches.value_of("connect") {
Some(s) => Some(match s.parse::<net::SocketAddr>() { Some(s) => Some(match s.parse::<net::SocketAddr>() {
Err(_) => s.parse::<net::IpAddr>() Err(_) => s.parse::<net::IpAddr>()
.map(|ip| net::SocketAddr::new(ip, network.port())) .map(|ip| net::SocketAddr::new(ip, network.port(&consensus.fork)))
.map_err(|_| "Invalid connect".to_owned()), .map_err(|_| "Invalid connect".to_owned()),
Ok(a) => Ok(a), Ok(a) => Ok(a),
}?), }?),
@ -99,6 +100,7 @@ pub fn parse(matches: &clap::ArgMatches) -> Result<Config, String> {
let seednodes: Vec<String> = match matches.value_of("seednode") { let seednodes: Vec<String> = match matches.value_of("seednode") {
Some(s) => vec![s.parse().map_err(|_| "Invalid seednode".to_owned())?], Some(s) => vec![s.parse().map_err(|_| "Invalid seednode".to_owned())?],
None => match (network, &consensus.fork) { None => match (network, &consensus.fork) {
(Network::Mainnet, &ConsensusFork::ZCash) => zcash_seednodes().into_iter().map(Into::into).collect(),
(Network::Mainnet, &ConsensusFork::BitcoinCash(_)) => bitcoin_cash_seednodes().into_iter().map(Into::into).collect(), (Network::Mainnet, &ConsensusFork::BitcoinCash(_)) => bitcoin_cash_seednodes().into_iter().map(Into::into).collect(),
(Network::Testnet, &ConsensusFork::BitcoinCash(_)) => bitcoin_cash_testnet_seednodes().into_iter().map(Into::into).collect(), (Network::Testnet, &ConsensusFork::BitcoinCash(_)) => bitcoin_cash_testnet_seednodes().into_iter().map(Into::into).collect(),
(Network::Mainnet, _) => mainnet_seednodes().into_iter().map(Into::into).collect(), (Network::Mainnet, _) => mainnet_seednodes().into_iter().map(Into::into).collect(),
@ -139,7 +141,7 @@ pub fn parse(matches: &clap::ArgMatches) -> Result<Config, String> {
let edge: H256 = s.parse().map_err(|_| "Invalid verification edge".to_owned())?; let edge: H256 = s.parse().map_err(|_| "Invalid verification edge".to_owned())?;
edge.reversed() edge.reversed()
}, },
_ => network.default_verification_edge(), _ => network.default_verification_edge(&consensus.fork),
}; };
let config = Config { let config = Config {
@ -171,14 +173,15 @@ pub fn parse(matches: &clap::ArgMatches) -> Result<Config, String> {
fn parse_consensus_fork(network: Network, db: &storage::SharedStore, matches: &clap::ArgMatches) -> Result<ConsensusFork, String> { fn parse_consensus_fork(network: Network, db: &storage::SharedStore, matches: &clap::ArgMatches) -> Result<ConsensusFork, String> {
let old_consensus_fork = db.consensus_fork()?; let old_consensus_fork = db.consensus_fork()?;
let new_consensus_fork = match (matches.is_present("btc"), matches.is_present("bch")) { let new_consensus_fork = match (matches.is_present("btc"), matches.is_present("bch"), matches.is_present("zcash")) {
(false, false) => match &old_consensus_fork { (false, false, false) => match &old_consensus_fork {
&Some(ref old_consensus_fork) => old_consensus_fork, &Some(ref old_consensus_fork) => old_consensus_fork,
&None => return Err("You must select fork on first run: --btc, --bch".into()), &None => return Err("You must select fork on first run: --btc, --bch or --zcash".into()),
}, },
(true, false) => "btc", (true, false, false) => "btc",
(false, true) => "bch", (false, true, false) => "bch",
_ => return Err("You can only pass single fork argument: --btc, --bch".into()), (false, false, true) => "zcash",
_ => return Err("You can only pass single fork argument: --btc, --bch or --zcash".into()),
}; };
match &old_consensus_fork { match &old_consensus_fork {
@ -191,6 +194,7 @@ fn parse_consensus_fork(network: Network, db: &storage::SharedStore, matches: &c
Ok(match new_consensus_fork { Ok(match new_consensus_fork {
"btc" => ConsensusFork::BitcoinCore, "btc" => ConsensusFork::BitcoinCore,
"bch" => ConsensusFork::BitcoinCash(BitcoinCashConsensusParams::new(network)), "bch" => ConsensusFork::BitcoinCash(BitcoinCashConsensusParams::new(network)),
"zcash" => ConsensusFork::ZCash,
_ => unreachable!("hardcoded above"), _ => unreachable!("hardcoded above"),
}) })
} }

View File

@ -35,7 +35,9 @@ use app_dirs::AppInfo;
pub const APP_INFO: AppInfo = AppInfo { name: "pbtc", author: "Parity" }; pub const APP_INFO: AppInfo = AppInfo { name: "pbtc", author: "Parity" };
pub const PROTOCOL_VERSION: u32 = 70_014; pub const PROTOCOL_VERSION: u32 = 70_014;
pub const PROTOCOL_MINIMUM: u32 = 70_001; pub const PROTOCOL_MINIMUM: u32 = 70_001;
pub const USER_AGENT: &'static str = "pbtc"; pub const ZCASH_PROTOCOL_VERSION: u32 = 170_002;
pub const ZCASH_PROTOCOL_MINIMUM: u32 = 170_002;
pub const USER_AGENT: &'static str = "bcore";
pub const REGTEST_USER_AGENT: &'static str = "/Satoshi:0.12.1/"; pub const REGTEST_USER_AGENT: &'static str = "/Satoshi:0.12.1/";
pub const LOG_INFO: &'static str = "sync=info"; pub const LOG_INFO: &'static str = "sync=info";

View File

@ -41,3 +41,11 @@ pub fn bitcoin_cash_testnet_seednodes() -> Vec<&'static str> {
"testnet-seed.bitprim.org:18333", "testnet-seed.bitprim.org:18333",
] ]
} }
pub fn zcash_seednodes() -> Vec<&'static str> {
vec![
"dnsseed.z.cash:8233",
"dnsseed.str4d.xyz:8233",
"dnsseed.znodes.org:8233",
]
}

View File

@ -26,7 +26,7 @@ pub fn node_table_path(cfg: &Config) -> PathBuf {
pub fn init_db(cfg: &Config) -> Result<(), String> { pub fn init_db(cfg: &Config) -> Result<(), String> {
// insert genesis block if db is empty // insert genesis block if db is empty
let genesis_block: IndexedBlock = cfg.network.genesis_block().into(); let genesis_block: IndexedBlock = cfg.network.genesis_block(&cfg.consensus.fork).into();
match cfg.db.block_hash(0) { match cfg.db.block_hash(0) {
Some(ref db_genesis_block_hash) if db_genesis_block_hash != genesis_block.hash() => Err("Trying to open database with incompatible genesis block".into()), Some(ref db_genesis_block_hash) if db_genesis_block_hash != genesis_block.hash() => Err("Trying to open database with incompatible genesis block".into()),
Some(_) => Ok(()), Some(_) => Ok(()),

View File

@ -112,7 +112,7 @@ impl<T> RawClient<T> where T: RawClientCoreApi {
impl<T> Raw for RawClient<T> where T: RawClientCoreApi { impl<T> Raw for RawClient<T> where T: RawClientCoreApi {
fn send_raw_transaction(&self, raw_transaction: RawTransaction) -> Result<H256, Error> { fn send_raw_transaction(&self, raw_transaction: RawTransaction) -> Result<H256, Error> {
let raw_transaction_data: Vec<u8> = raw_transaction.into(); let raw_transaction_data: Vec<u8> = raw_transaction.into();
let transaction = try!(deserialize(Reader::new(&raw_transaction_data)).map_err(|e| invalid_params("tx", e))); let transaction = try!(deserialize(Reader::new(&raw_transaction_data, 0)).map_err(|e| invalid_params("tx", e)));
self.core.accept_transaction(transaction) self.core.accept_transaction(transaction)
.map(|h| h.reversed().into()) .map(|h| h.reversed().into())
.map_err(|e| execution(e)) .map_err(|e| execution(e))

View File

@ -148,7 +148,7 @@ mod tests {
0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
]; ];
let mut reader = Reader::new(&buffer); let mut reader = Reader::new(&buffer, 0);
assert_eq!(reader.read::<CompactInteger>().unwrap(), 0u64.into()); assert_eq!(reader.read::<CompactInteger>().unwrap(), 0u64.into());
assert_eq!(reader.read::<CompactInteger>().unwrap(), 0xfcu64.into()); assert_eq!(reader.read::<CompactInteger>().unwrap(), 0xfcu64.into());
assert_eq!(reader.read::<CompactInteger>().unwrap(), 0xfdu64.into()); assert_eq!(reader.read::<CompactInteger>().unwrap(), 0xfdu64.into());

View File

@ -0,0 +1,13 @@
static mut default_flags: u32 = 0;
pub fn set_default_flags(flags: u32) {
unsafe {
default_flags = flags
}
}
pub fn get_default_flags() -> u32 {
unsafe {
default_flags
}
}

View File

@ -261,7 +261,7 @@ mod tests {
4, 0, 0, 0, 0, 0, 0, 0 4, 0, 0, 0, 0, 0, 0, 0
]; ];
let mut reader = Reader::new(&buffer); let mut reader = Reader::new(&buffer, 0);
assert!(!reader.is_finished()); assert!(!reader.is_finished());
assert_eq!(1u8, reader.read().unwrap()); assert_eq!(1u8, reader.read().unwrap());
assert_eq!(2u16, reader.read().unwrap()); assert_eq!(2u16, reader.read().unwrap());

View File

@ -2,6 +2,7 @@ extern crate byteorder;
extern crate primitives; extern crate primitives;
mod compact_integer; mod compact_integer;
mod flags;
mod impls; mod impls;
mod list; mod list;
mod reader; mod reader;
@ -9,13 +10,19 @@ mod stream;
pub use primitives::{hash, bytes, compact}; pub use primitives::{hash, bytes, compact};
// TODO: use same flags for both serialization && deserialization (they're used this way on network layer)
pub use flags::{set_default_flags, get_default_flags};
pub use compact_integer::CompactInteger; pub use compact_integer::CompactInteger;
pub use list::List; pub use list::List;
pub use reader::{Reader, Deserializable, deserialize, deserialize_iterator, ReadIterator, Error, pub use reader::{Reader, Deserializable, deserialize, deserialize_with_flags, deserialize_iterator,
DESERIALIZE_ZCASH, ReadIterator, Error, DESERIALIZE_ZCASH,
}; };
pub use stream::{ pub use stream::{
Stream, Serializable, serialize, serialize_with_flags, serialize_list, serialized_list_size, Stream, Serializable, serialize, serialize_with_flags, serialize_list, serialized_list_size,
serialized_list_size_with_flags, SERIALIZE_TRANSACTION_WITNESS, SERIALIZE_ZCASH, serialized_list_size_with_flags, SERIALIZE_TRANSACTION_WITNESS, SERIALIZE_ZCASH,
}; };
static mut GLOBAL_SERIALIZATION_FLAGS: u32 = SERIALIZE_ZCASH;

View File

@ -1,5 +1,6 @@
use std::{io, marker}; use std::{io, marker};
use compact_integer::CompactInteger; use compact_integer::CompactInteger;
use flags::get_default_flags;
/// Deserialize transaction witness data. /// Deserialize transaction witness data.
pub const DESERIALIZE_TRANSACTION_WITNESS: u32 = 0x40000000; pub const DESERIALIZE_TRANSACTION_WITNESS: u32 = 0x40000000;
@ -17,6 +18,18 @@ pub fn deserialize<R, T>(buffer: R) -> Result<T, Error> where R: io::Read, T: De
} }
} }
pub fn deserialize_with_flags<R, T>(buffer: R, flags: u32) -> Result<T, Error> where R: io::Read, T: Deserializable {
let mut reader = Reader::from_read_with_flags(buffer, flags);
let result = try!(reader.read());
if reader.is_finished() {
Ok(result)
} else {
Err(Error::UnreadData)
}
}
pub fn deserialize_iterator<R, T>(buffer: R) -> ReadIterator<R, T> where R: io::Read, T: Deserializable { pub fn deserialize_iterator<R, T>(buffer: R) -> ReadIterator<R, T> where R: io::Read, T: Deserializable {
ReadIterator { ReadIterator {
reader: Reader::from_read(buffer), reader: Reader::from_read(buffer),
@ -51,11 +64,11 @@ pub struct Reader<T> {
impl<'a> Reader<&'a [u8]> { impl<'a> Reader<&'a [u8]> {
/// Convenient way of creating for slice of bytes /// Convenient way of creating for slice of bytes
pub fn new(buffer: &'a [u8]) -> Self { pub fn new(buffer: &'a [u8], flags: u32) -> Self {
Reader { Reader {
buffer: buffer, buffer: buffer,
peeked: None, peeked: None,
flags: 0, flags: flags | get_default_flags(),
} }
} }
} }
@ -81,10 +94,14 @@ impl<T> io::Read for Reader<T> where T: io::Read {
impl<R> Reader<R> where R: io::Read { impl<R> Reader<R> where R: io::Read {
pub fn from_read(read: R) -> Self { pub fn from_read(read: R) -> Self {
Self::from_read_with_flags(read, 0)
}
pub fn from_read_with_flags(read: R, flags: u32) -> Self {
Reader { Reader {
buffer: read, buffer: read,
peeked: None, peeked: None,
flags: 0, flags: flags,
} }
} }

View File

@ -3,6 +3,7 @@ use std::io::{self, Write};
use std::borrow::Borrow; use std::borrow::Borrow;
use compact_integer::CompactInteger; use compact_integer::CompactInteger;
use bytes::Bytes; use bytes::Bytes;
use flags::get_default_flags;
/// Serialize transaction witness data. /// Serialize transaction witness data.
pub const SERIALIZE_TRANSACTION_WITNESS: u32 = 0x40000000; pub const SERIALIZE_TRANSACTION_WITNESS: u32 = 0x40000000;
@ -10,7 +11,7 @@ pub const SERIALIZE_TRANSACTION_WITNESS: u32 = 0x40000000;
pub const SERIALIZE_ZCASH: u32 = 0x80000000; pub const SERIALIZE_ZCASH: u32 = 0x80000000;
pub fn serialize<T>(t: &T) -> Bytes where T: Serializable{ pub fn serialize<T>(t: &T) -> Bytes where T: Serializable{
let mut stream = Stream::default(); let mut stream = Stream::new();
stream.append(t); stream.append(t);
stream.out() stream.out()
} }
@ -22,7 +23,7 @@ pub fn serialize_with_flags<T>(t: &T, flags: u32) -> Bytes where T: Serializable
} }
pub fn serialize_list<T, K>(t: &[K]) -> Bytes where T: Serializable, K: Borrow<T> { pub fn serialize_list<T, K>(t: &[K]) -> Bytes where T: Serializable, K: Borrow<T> {
let mut stream = Stream::default(); let mut stream = Stream::new();
stream.append_list(t); stream.append_list(t);
stream.out() stream.out()
} }
@ -55,21 +56,26 @@ pub trait Serializable {
} }
/// Stream used for serialization of Bitcoin structures /// Stream used for serialization of Bitcoin structures
#[derive(Default)]
pub struct Stream { pub struct Stream {
buffer: Vec<u8>, buffer: Vec<u8>,
flags: u32, flags: u32,
} }
impl Default for Stream {
fn default() -> Self {
Self::new()
}
}
impl Stream { impl Stream {
/// New stream /// New stream
pub fn new() -> Self { pub fn new() -> Self {
Stream { buffer: Vec::new(), flags: 0 } Stream { buffer: Vec::new(), flags: get_default_flags() }
} }
/// Create stream with given flags, /// Create stream with given flags,
pub fn with_flags(flags: u32) -> Self { pub fn with_flags(flags: u32) -> Self {
Stream { buffer: Vec::new(), flags: flags } Stream { buffer: Vec::new(), flags: flags | get_default_flags() }
} }
/// Are transactions written to this stream with witness data? /// Are transactions written to this stream with witness data?

View File

@ -382,7 +382,7 @@ pub mod tests {
.build() .build()
.merkled_header() .merkled_header()
.parent(rolling_hash.clone()) .parent(rolling_hash.clone())
.bits(Network::Unitest.max_bits().into()) .bits(Network::Unitest.max_bits(&ConsensusFork::BitcoinCore).into())
.build() .build()
.build(); .build();
rolling_hash = next_block.hash(); rolling_hash = next_block.hash();
@ -401,7 +401,7 @@ pub mod tests {
.build() .build()
.merkled_header() .merkled_header()
.parent(last_block_hash) .parent(last_block_hash)
.bits(Network::Unitest.max_bits().into()) .bits(Network::Unitest.max_bits(&ConsensusFork::BitcoinCore).into())
.build() .build()
.build().into(); .build().into();

View File

@ -293,7 +293,7 @@ mod tests {
// real world message // real world message
let payload: Bytes = "fd77078732c06c257f2818a0d14738804d6a18a0f0a9800e039be473286d591f48040c99e96d2e0cd8480b03c0823fdd79310e0e04c86314ae24cabaa931f39852c813172e524c4b231020557dda2023130b0f1f309de822014bf6d4305d238ea013b8539e9c138053076a22020335bc1042e543f260787993a07a155a7a560c1475f75ec109b73822491c5880924303a5545ffc465132960fe40a8822010f919c38910f31c546be6940090f0476a02570de8d28258ee8081dea073829386a9de01b0070348f0f2fb48c6a1b4e92292de7b60dbafb8df3a6cab6a824e50005744018b384f080c8265152e406b1c85906d5325d1c83ac880d02214ad401ddc07657002c47708e338020bd14fcc147bfe49335647062074a4d3276e0d3a5110826a05d4fb025129f48c26e5819dd878d851b84802b7a211097813ef952410390c95bb294a7a8faca3667f0068489a69d9c9e8405c035442874a6a8c448c60600834a22041ce36a8065b086469bbb1b46d326b7a9923054ad4e32e4b7231aa203c5acab1f5821b92d2f00728819e587e1e6ff9fa6e66ff52fb54bce3648a7b043cbd19469aa5af0891eb4979def822f06522f080830b411545b4240e01195b0f0962e628050f0f8290269c45c20aa16559d17ceca68b81a21370909a1086614531577600ad8480ae1023c9173260bc6385c0e2d46806c05401a17ac969edfe65fd4000007e1c8a13ac651922edfa5a3235a0bcc10cc0067b4404d64260aea022391b007d3010c8380fda9c821d37258e47a0ab6485baff88876ba55cd190edf730970875f75522010e40f8c28e4872a2065c96390041bef9273a6a1c05d2bd28193b205b2cf25e44c5290926a4d392450b3135a0db7cc2c0696384eee68a65a4280ac3c44207264243fd18795c69588f4e418a26d4e21d1cee894325a2fc869b03fec68fd3e86b31998f9f9a6402dd672227451b1b5419a89c90ae96b9292a1ca83848bc026dcd00ec740342496730a7ab8e48200c7ea240d0e34a07890a9203938ee188475b3d6dd2f50399019c249536955894917fa3acc400ce04ec42d5e89e2d48aa085ae129226d0ea2a4d0038db88fd5ec0688768cea449171280438e8f5164d8682c40b91a2dab042800b1f312b22460e4905dccee59842a2bc9f807d542e08388fec013696d281c0356880040b0610ac4cb148a95a5924875891b2217040bbab7bba21f14898203ae87153206601c20c484f072216c1714ac5ded41a6d213fc09962f195129ac09d85dc05501a773163646021100481cb385a0fdb1609e8d1bc042942f169884e60482ae2004924fc2eb0b7061855858b5e54a4517352084778f38c09f1f004431da4531059c1296436d4c89e8839d34506a27b07c94fa80d2a0a9b73208a79982f0a5d16e0b723d38816a6a666c09bceae5a46d8a032248302224ae43c7e4801004ea6671c6d08142b67e27269a4ac6418748d74f481fc2dbbac5852afc645026cb462f790347d32a26e0b88209f2168110eb4e88394dd0f3bc27958994803238059d581d8cda73493a994c433fad902e20093ad40b1570543af928bc4830c3976d2802635400c0ac5a25833008f00b8bb691c1d9ce026373d05ac03fa6851402e05c6f109fa1754da54a20aa9f4f4782e68966a5113ae141d495d2a53d64bb6a023616b243e0333e2e0c65f2078559a98f48e8637f7b2ff326572a32532e2ec9e9651c092c52a522a5120249a159fa49d56d304806b502c425e3981275409f38b20418bc8206d21e884401c05c3c7d0b7404cf2a97706092b5a818638122ce750ce8780812900f501f4f02cb90fd5ea615e611006e010920072d08ca01b535741460c9aa1ab567ac2f79a004400e523fdcf95320bc08a37f54aaa01b2a2d0aa343ec13205131124b445a2c1b9a7542c63c6ced549447462099c12a9c613838995d718849650300056845311b2c93a1d35a66622466e0a3cef68594faa11021751c0e5358027721d2a2362fc9353655680c80fa5cad35685a0454932251aa121cb50583ae987c2a6e8009f3342048019509760b7e233de62cdcb636344d8a012af9f61a539ec66801c46a56b3d8ea6825e95430d1cc71fcc0bc977e4ea27f83e284cab0aea0a5085e67039901252a722054e33168a89d160a5908a325b63654016da1e94450548bac84a1b22fcc92ce7e2018967755711480e9048f5ded20b5d3960f21b559f1a0be84a53721f7b0f283d7d1bc2bd7f5d7550d3213814eb56e13f0b106acc07b05ece2c518117e934409843f1f889c2d84845c540514badb4ca00864e8bde78e50b0837478104c018cd5996977196e4f064002480a2761489000984d44d0077df65696f306930c893c50b08516e9ea82e02eb0400bc3d1adade23161b45e5210e08e981568f8af232bdf0f3c460349a8800c9f2c510eecc8ccee39e8b0898d329560aaf4d9594a551186423f79aa6806ce8c541506283a54e8859a840814012cad0289627f8659658218f6e58926af0849b4b23b40ac76280061b90c940f71617e0397ea145968250b1060608e4002432021195635dc52e0495c69fa67768a4a89ec32206fa30f62a85503de8c79df940f808c0de2f1723c0c84d89f317c4c1287a40759946d9cc8c43044a817dd6bb8ed326e4ab800fd8815482910de3cc360d40080a8d956e049ec6d1000000000943a3102".parse().unwrap(); let payload: Bytes = "fd77078732c06c257f2818a0d14738804d6a18a0f0a9800e039be473286d591f48040c99e96d2e0cd8480b03c0823fdd79310e0e04c86314ae24cabaa931f39852c813172e524c4b231020557dda2023130b0f1f309de822014bf6d4305d238ea013b8539e9c138053076a22020335bc1042e543f260787993a07a155a7a560c1475f75ec109b73822491c5880924303a5545ffc465132960fe40a8822010f919c38910f31c546be6940090f0476a02570de8d28258ee8081dea073829386a9de01b0070348f0f2fb48c6a1b4e92292de7b60dbafb8df3a6cab6a824e50005744018b384f080c8265152e406b1c85906d5325d1c83ac880d02214ad401ddc07657002c47708e338020bd14fcc147bfe49335647062074a4d3276e0d3a5110826a05d4fb025129f48c26e5819dd878d851b84802b7a211097813ef952410390c95bb294a7a8faca3667f0068489a69d9c9e8405c035442874a6a8c448c60600834a22041ce36a8065b086469bbb1b46d326b7a9923054ad4e32e4b7231aa203c5acab1f5821b92d2f00728819e587e1e6ff9fa6e66ff52fb54bce3648a7b043cbd19469aa5af0891eb4979def822f06522f080830b411545b4240e01195b0f0962e628050f0f8290269c45c20aa16559d17ceca68b81a21370909a1086614531577600ad8480ae1023c9173260bc6385c0e2d46806c05401a17ac969edfe65fd4000007e1c8a13ac651922edfa5a3235a0bcc10cc0067b4404d64260aea022391b007d3010c8380fda9c821d37258e47a0ab6485baff88876ba55cd190edf730970875f75522010e40f8c28e4872a2065c96390041bef9273a6a1c05d2bd28193b205b2cf25e44c5290926a4d392450b3135a0db7cc2c0696384eee68a65a4280ac3c44207264243fd18795c69588f4e418a26d4e21d1cee894325a2fc869b03fec68fd3e86b31998f9f9a6402dd672227451b1b5419a89c90ae96b9292a1ca83848bc026dcd00ec740342496730a7ab8e48200c7ea240d0e34a07890a9203938ee188475b3d6dd2f50399019c249536955894917fa3acc400ce04ec42d5e89e2d48aa085ae129226d0ea2a4d0038db88fd5ec0688768cea449171280438e8f5164d8682c40b91a2dab042800b1f312b22460e4905dccee59842a2bc9f807d542e08388fec013696d281c0356880040b0610ac4cb148a95a5924875891b2217040bbab7bba21f14898203ae87153206601c20c484f072216c1714ac5ded41a6d213fc09962f195129ac09d85dc05501a773163646021100481cb385a0fdb1609e8d1bc042942f169884e60482ae2004924fc2eb0b7061855858b5e54a4517352084778f38c09f1f004431da4531059c1296436d4c89e8839d34506a27b07c94fa80d2a0a9b73208a79982f0a5d16e0b723d38816a6a666c09bceae5a46d8a032248302224ae43c7e4801004ea6671c6d08142b67e27269a4ac6418748d74f481fc2dbbac5852afc645026cb462f790347d32a26e0b88209f2168110eb4e88394dd0f3bc27958994803238059d581d8cda73493a994c433fad902e20093ad40b1570543af928bc4830c3976d2802635400c0ac5a25833008f00b8bb691c1d9ce026373d05ac03fa6851402e05c6f109fa1754da54a20aa9f4f4782e68966a5113ae141d495d2a53d64bb6a023616b243e0333e2e0c65f2078559a98f48e8637f7b2ff326572a32532e2ec9e9651c092c52a522a5120249a159fa49d56d304806b502c425e3981275409f38b20418bc8206d21e884401c05c3c7d0b7404cf2a97706092b5a818638122ce750ce8780812900f501f4f02cb90fd5ea615e611006e010920072d08ca01b535741460c9aa1ab567ac2f79a004400e523fdcf95320bc08a37f54aaa01b2a2d0aa343ec13205131124b445a2c1b9a7542c63c6ced549447462099c12a9c613838995d718849650300056845311b2c93a1d35a66622466e0a3cef68594faa11021751c0e5358027721d2a2362fc9353655680c80fa5cad35685a0454932251aa121cb50583ae987c2a6e8009f3342048019509760b7e233de62cdcb636344d8a012af9f61a539ec66801c46a56b3d8ea6825e95430d1cc71fcc0bc977e4ea27f83e284cab0aea0a5085e67039901252a722054e33168a89d160a5908a325b63654016da1e94450548bac84a1b22fcc92ce7e2018967755711480e9048f5ded20b5d3960f21b559f1a0be84a53721f7b0f283d7d1bc2bd7f5d7550d3213814eb56e13f0b106acc07b05ece2c518117e934409843f1f889c2d84845c540514badb4ca00864e8bde78e50b0837478104c018cd5996977196e4f064002480a2761489000984d44d0077df65696f306930c893c50b08516e9ea82e02eb0400bc3d1adade23161b45e5210e08e981568f8af232bdf0f3c460349a8800c9f2c510eecc8ccee39e8b0898d329560aaf4d9594a551186423f79aa6806ce8c541506283a54e8859a840814012cad0289627f8659658218f6e58926af0849b4b23b40ac76280061b90c940f71617e0397ea145968250b1060608e4002432021195635dc52e0495c69fa67768a4a89ec32206fa30f62a85503de8c79df940f808c0de2f1723c0c84d89f317c4c1287a40759946d9cc8c43044a817dd6bb8ed326e4ab800fd8815482910de3cc360d40080a8d956e049ec6d1000000000943a3102".parse().unwrap();
let message: types::FilterLoad = deserialize_payload(&payload, 70001).unwrap(); let message: types::FilterLoad = deserialize_payload(&payload, 70001, 0).unwrap();
// containing this address // containing this address
let address: Bytes = "BA99435B59DEBDBB5E207C0B33FF55752DBC5EFF".parse().unwrap(); let address: Bytes = "BA99435B59DEBDBB5E207C0B33FF55752DBC5EFF".parse().unwrap();

View File

@ -38,7 +38,7 @@ impl BackwardsCompatibleChainVerifier {
let current_time = ::time::get_time().sec as u32; let current_time = ::time::get_time().sec as u32;
// first run pre-verification // first run pre-verification
let chain_verifier = ChainVerifier::new(block, self.consensus.network, current_time); let chain_verifier = ChainVerifier::new(block, &self.consensus, current_time);
chain_verifier.check()?; chain_verifier.check()?;
assert_eq!(Some(self.store.best_block().hash), self.store.block_hash(self.store.best_block().number)); assert_eq!(Some(self.store.best_block().hash), self.store.block_hash(self.store.best_block().number));
@ -95,7 +95,7 @@ impl BackwardsCompatibleChainVerifier {
// TODO: full verification // TODO: full verification
let current_time = ::time::get_time().sec as u32; let current_time = ::time::get_time().sec as u32;
let header = IndexedBlockHeader::new(hash.clone(), header.clone()); let header = IndexedBlockHeader::new(hash.clone(), header.clone());
let header_verifier = HeaderVerifier::new(&header, self.consensus.network, current_time); let header_verifier = HeaderVerifier::new(&header, &self.consensus, current_time);
header_verifier.check() header_verifier.check()
} }

View File

@ -1,6 +1,6 @@
use rayon::prelude::{IntoParallelRefIterator, IndexedParallelIterator, ParallelIterator}; use rayon::prelude::{IntoParallelRefIterator, IndexedParallelIterator, ParallelIterator};
use chain::IndexedBlock; use chain::IndexedBlock;
use network::Network; use network::ConsensusParams;
use error::Error; use error::Error;
use verify_block::BlockVerifier; use verify_block::BlockVerifier;
use verify_header::HeaderVerifier; use verify_header::HeaderVerifier;
@ -13,11 +13,11 @@ pub struct ChainVerifier<'a> {
} }
impl<'a> ChainVerifier<'a> { impl<'a> ChainVerifier<'a> {
pub fn new(block: &'a IndexedBlock, network: Network, current_time: u32) -> Self { pub fn new(block: &'a IndexedBlock, consensus: &ConsensusParams, current_time: u32) -> Self {
trace!(target: "verification", "Block pre-verification {}", block.hash().to_reversed_str()); trace!(target: "verification", "Block pre-verification {}", block.hash().to_reversed_str());
ChainVerifier { ChainVerifier {
block: BlockVerifier::new(block), block: BlockVerifier::new(block),
header: HeaderVerifier::new(&block.header, network, current_time), header: HeaderVerifier::new(&block.header, consensus, current_time),
transactions: block.transactions.iter().map(TransactionVerifier::new).collect(), transactions: block.transactions.iter().map(TransactionVerifier::new).collect(),
} }
} }

View File

@ -1,6 +1,6 @@
use primitives::compact::Compact; use primitives::compact::Compact;
use chain::IndexedBlockHeader; use chain::IndexedBlockHeader;
use network::Network; use network::ConsensusParams;
use work::is_valid_proof_of_work; use work::is_valid_proof_of_work;
use error::Error; use error::Error;
use constants::BLOCK_MAX_FUTURE; use constants::BLOCK_MAX_FUTURE;
@ -11,9 +11,9 @@ pub struct HeaderVerifier<'a> {
} }
impl<'a> HeaderVerifier<'a> { impl<'a> HeaderVerifier<'a> {
pub fn new(header: &'a IndexedBlockHeader, network: Network, current_time: u32) -> Self { pub fn new(header: &'a IndexedBlockHeader, consensus: &ConsensusParams, current_time: u32) -> Self {
HeaderVerifier { HeaderVerifier {
proof_of_work: HeaderProofOfWork::new(header, network), proof_of_work: HeaderProofOfWork::new(header, consensus),
timestamp: HeaderTimestamp::new(header, current_time, BLOCK_MAX_FUTURE as u32), timestamp: HeaderTimestamp::new(header, current_time, BLOCK_MAX_FUTURE as u32),
} }
} }
@ -31,10 +31,10 @@ pub struct HeaderProofOfWork<'a> {
} }
impl<'a> HeaderProofOfWork<'a> { impl<'a> HeaderProofOfWork<'a> {
fn new(header: &'a IndexedBlockHeader, network: Network) -> Self { fn new(header: &'a IndexedBlockHeader, consensus: &ConsensusParams) -> Self {
HeaderProofOfWork { HeaderProofOfWork {
header: header, header: header,
max_work_bits: network.max_bits().into(), max_work_bits: consensus.network.max_bits(&consensus.fork).into(),
} }
} }

View File

@ -58,7 +58,7 @@ pub fn retarget_timespan(retarget_timestamp: u32, last_timestamp: u32) -> u32 {
/// Returns work required for given header /// Returns work required for given header
pub fn work_required(parent_hash: H256, time: u32, height: u32, store: &BlockHeaderProvider, consensus: &ConsensusParams) -> Compact { pub fn work_required(parent_hash: H256, time: u32, height: u32, store: &BlockHeaderProvider, consensus: &ConsensusParams) -> Compact {
let max_bits = consensus.network.max_bits().into(); let max_bits = consensus.network.max_bits(&consensus.fork).into();
if height == 0 { if height == 0 {
return max_bits; return max_bits;
} }
@ -79,13 +79,13 @@ pub fn work_required(parent_hash: H256, time: u32, height: u32, store: &BlockHea
} }
if consensus.network == Network::Testnet { if consensus.network == Network::Testnet {
return work_required_testnet(parent_hash, time, height, store, Network::Testnet) return work_required_testnet(parent_hash, time, height, store, consensus)
} }
parent_header.bits parent_header.bits
} }
pub fn work_required_testnet(parent_hash: H256, time: u32, height: u32, store: &BlockHeaderProvider, network: Network) -> Compact { pub fn work_required_testnet(parent_hash: H256, time: u32, height: u32, store: &BlockHeaderProvider, consensus: &ConsensusParams) -> Compact {
assert!(height != 0, "cannot calculate required work for genesis block"); assert!(height != 0, "cannot calculate required work for genesis block");
let mut bits = Vec::new(); let mut bits = Vec::new();
@ -93,7 +93,7 @@ pub fn work_required_testnet(parent_hash: H256, time: u32, height: u32, store: &
let parent_header = store.block_header(block_ref.clone()).expect("height != 0; qed"); let parent_header = store.block_header(block_ref.clone()).expect("height != 0; qed");
let max_time_gap = parent_header.time + DOUBLE_SPACING_SECONDS; let max_time_gap = parent_header.time + DOUBLE_SPACING_SECONDS;
let max_bits = network.max_bits().into(); let max_bits = consensus.network.max_bits(&consensus.fork).into();
if time > max_time_gap { if time > max_time_gap {
return max_bits; return max_bits;
} }
@ -152,7 +152,7 @@ pub fn block_reward_satoshi(block_height: u32) -> u64 {
mod tests { mod tests {
use primitives::hash::H256; use primitives::hash::H256;
use primitives::compact::Compact; use primitives::compact::Compact;
use network::Network; use network::{Network, ConsensusFork};
use super::{is_valid_proof_of_work_hash, is_valid_proof_of_work, block_reward_satoshi}; use super::{is_valid_proof_of_work_hash, is_valid_proof_of_work, block_reward_satoshi};
fn is_valid_pow(max: Compact, bits: u32, hash: &'static str) -> bool { fn is_valid_pow(max: Compact, bits: u32, hash: &'static str) -> bool {
@ -163,14 +163,14 @@ mod tests {
#[test] #[test]
fn test_is_valid_proof_of_work() { fn test_is_valid_proof_of_work() {
// block 2 // block 2
assert!(is_valid_pow(Network::Mainnet.max_bits().into(), 486604799u32, "000000006a625f06636b8bb6ac7b960a8d03705d1ace08b1a19da3fdcc99ddbd")); assert!(is_valid_pow(Network::Mainnet.max_bits(&ConsensusFork::BitcoinCore).into(), 486604799u32, "000000006a625f06636b8bb6ac7b960a8d03705d1ace08b1a19da3fdcc99ddbd"));
// block 400_000 // block 400_000
assert!(is_valid_pow(Network::Mainnet.max_bits().into(), 403093919u32, "000000000000000004ec466ce4732fe6f1ed1cddc2ed4b328fff5224276e3f6f")); assert!(is_valid_pow(Network::Mainnet.max_bits(&ConsensusFork::BitcoinCore).into(), 403093919u32, "000000000000000004ec466ce4732fe6f1ed1cddc2ed4b328fff5224276e3f6f"));
// other random tests // other random tests
assert!(is_valid_pow(Network::Regtest.max_bits().into(), 0x181bc330u32, "00000000000000001bc330000000000000000000000000000000000000000000")); assert!(is_valid_pow(Network::Regtest.max_bits(&ConsensusFork::BitcoinCore).into(), 0x181bc330u32, "00000000000000001bc330000000000000000000000000000000000000000000"));
assert!(!is_valid_pow(Network::Regtest.max_bits().into(), 0x181bc330u32, "00000000000000001bc330000000000000000000000000000000000000000001")); assert!(!is_valid_pow(Network::Regtest.max_bits(&ConsensusFork::BitcoinCore).into(), 0x181bc330u32, "00000000000000001bc330000000000000000000000000000000000000000001"));
assert!(!is_valid_pow(Network::Regtest.max_bits().into(), 0x181bc330u32, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); assert!(!is_valid_pow(Network::Regtest.max_bits(&ConsensusFork::BitcoinCore).into(), 0x181bc330u32, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
} }
#[test] #[test]

View File

@ -24,7 +24,7 @@ pub fn work_required_bitcoin_cash(parent_header: IndexedBlockHeader, time: u32,
} }
if consensus.network == Network::Testnet { if consensus.network == Network::Testnet {
return work_required_testnet(parent_header.hash, time, height, store, Network::Testnet) return work_required_testnet(parent_header.hash, time, height, store, consensus)
} }
if parent_header.raw.bits == max_bits { if parent_header.raw.bits == max_bits {
@ -140,7 +140,7 @@ fn work_required_bitcoin_cash_adjusted(parent_header: IndexedBlockHeader, time:
// Special difficulty rule for testnet: // Special difficulty rule for testnet:
// If the new block's timestamp is more than 2 * 10 minutes then allow // If the new block's timestamp is more than 2 * 10 minutes then allow
// mining of a min-difficulty block. // mining of a min-difficulty block.
let max_bits = consensus.network.max_bits(); let max_bits = consensus.network.max_bits(&consensus.fork);
if consensus.network == Network::Testnet { if consensus.network == Network::Testnet {
let max_time_gap = parent_header.raw.time + DOUBLE_SPACING_SECONDS; let max_time_gap = parent_header.raw.time + DOUBLE_SPACING_SECONDS;
if time > max_time_gap { if time > max_time_gap {
@ -163,7 +163,7 @@ fn work_required_bitcoin_cash_adjusted(parent_header: IndexedBlockHeader, time:
// Compute the target based on time and work done during the interval. // Compute the target based on time and work done during the interval.
let next_target = compute_target(first_header, last_header, store); let next_target = compute_target(first_header, last_header, store);
let max_bits = consensus.network.max_bits(); let max_bits = consensus.network.max_bits(&consensus.fork);
if next_target > max_bits { if next_target > max_bits {
return max_bits.into(); return max_bits.into();
} }
@ -275,7 +275,7 @@ mod tests {
})); }));
let limit_bits = uahf_consensus.network.max_bits(); let limit_bits = uahf_consensus.network.max_bits(&ConsensusFork::BitcoinCore);
let initial_bits = limit_bits >> 4; let initial_bits = limit_bits >> 4;
let mut header_provider = MemoryBlockHeaderProvider::default(); let mut header_provider = MemoryBlockHeaderProvider::default();