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",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"primitives 0.1.0",
"serialization 0.1.0",
]
[[package]]

View File

@ -60,6 +60,8 @@ impl Block {
#[cfg(test)]
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 super::Block;
@ -74,4 +76,20 @@ mod tests {
assert_eq!(block.merkle_root(), merkle_root);
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 {
fn serialize(&self, stream: &mut Stream) {
let is_zcash_format = stream.is_zcash_stream();
println!("=== is_zcash_format = {}", is_zcash_format);
stream
.append(&self.version)
.append(&self.previous_header_hash)
@ -140,7 +140,7 @@ mod tests {
equihash_solution: None,
};
let mut stream = Stream::default();
let mut stream = Stream::new();
stream.append(&block_header);
let expected = vec![
@ -166,7 +166,7 @@ mod tests {
6, 0, 0, 0,
];
let mut reader = Reader::new(&buffer);
let mut reader = Reader::new(&buffer, 0);
let expected = BlockHeader {
version: 1,

View File

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

View File

@ -25,12 +25,12 @@ 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 {
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 = Magic::from(magic);
if expected != magic {
@ -88,6 +88,6 @@ mod tests {
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 reader;
pub use self::stream::{serialize_payload, serialize_payload_with_flags};
pub use self::stream::serialize_payload;
pub use self::reader::deserialize_payload;

View File

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

View File

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

View File

@ -196,7 +196,7 @@ impl Deserializable for V70001 {
impl From<&'static str> for Version {
fn from(s: &'static str) -> Self {
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,
});
assert_eq!(serialize_payload(&version, 0), Ok(expected));
assert_eq!(serialize_payload(&version, 0, 0), Ok(expected));
}
#[test]
@ -241,6 +241,6 @@ mod test {
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"
chain = { path = "../chain" }
primitives = { path = "../primitives" }
serialization = { path = "../serialization" }

View File

@ -3,6 +3,7 @@ extern crate lazy_static;
extern crate chain;
extern crate primitives;
extern crate serialization;
mod consensus;
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_REGTEST: u32 = 0xFABFB5DA;
const ZCASH_MAGIC_MAINNET: u32 = 0x6427e924;
const ZCASH_MAGIC_TESTNET: u32 = 0xbff91afa;
const ZCASH_MAGIC_REGTEST: u32 = 0x5f3fe8aa;
lazy_static! {
static ref MAX_BITS_MAINNET: U256 = "00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff".parse()
.expect("hardcoded value should parse without errors");
@ -23,6 +27,13 @@ lazy_static! {
.expect("hardcoded value should parse without errors");
static ref MAX_BITS_REGTEST: U256 = "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".parse()
.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.
@ -49,6 +60,9 @@ impl Network {
(&ConsensusFork::BitcoinCash(_), Network::Mainnet) => BITCOIN_CASH_MAGIC_MAINNET,
(&ConsensusFork::BitcoinCash(_), Network::Testnet) => BITCOIN_CASH_MAGIC_TESTNET,
(&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::Testnet) => MAGIC_TESTNET,
(_, Network::Regtest) => MAGIC_REGTEST,
@ -57,20 +71,26 @@ impl Network {
}
}
pub fn max_bits(&self) -> U256 {
match *self {
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 max_bits(&self, fork: &ConsensusFork) -> U256 {
match (fork, *self) {
(&ConsensusFork::ZCash, Network::Mainnet) => ZCASH_MAX_BITS_MAINNET.clone(),
(&ConsensusFork::ZCash, Network::Testnet) => ZCASH_MAX_BITS_TESTNET.clone(),
(&ConsensusFork::ZCash, Network::Testnet) => ZCASH_MAX_BITS_REGTEST.clone(),
(_, 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 {
match *self {
Network::Mainnet | Network::Other(_) => 8333,
Network::Testnet => 18333,
Network::Regtest | Network::Unitest => 18444,
pub fn port(&self, fork: &ConsensusFork) -> u16 {
match (fork, *self) {
(&ConsensusFork::ZCash, Network::Mainnet) | (&ConsensusFork::ZCash, Network::Other(_)) => 8233,
(&ConsensusFork::ZCash, Network::Testnet) => 18233,
(&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 {
match *self {
Network::Mainnet | Network::Other(_) => "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000".into(),
Network::Testnet => "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff001d1aa4ae180101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000".into(),
Network::Regtest | Network::Unitest => "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff7f20020000000101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000".into(),
pub fn genesis_block(&self, fork: &ConsensusFork) -> Block {
match (fork, *self) {
// TODO
(&ConsensusFork::ZCash, Network::Mainnet) | (&ConsensusFork::ZCash, Network::Other(_)) => {
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 {
Network::Mainnet => H256::from_reversed_str("0000000000000000030abc968e1bd635736e880b946085c93152969b9a81a6e2"),
Network::Testnet => H256::from_reversed_str("000000000871ee6842d3648317ccc8a435eb8cc3c2429aee94faff9ba26b05a0"),
_ => self.genesis_block().hash(),
_ => self.genesis_block(fork).hash(),
}
}
}
@ -118,18 +154,18 @@ mod tests {
#[test]
fn test_network_max_bits() {
assert_eq!(Network::Mainnet.max_bits(), *MAX_BITS_MAINNET);
assert_eq!(Network::Testnet.max_bits(), *MAX_BITS_TESTNET);
assert_eq!(Network::Regtest.max_bits(), *MAX_BITS_REGTEST);
assert_eq!(Network::Unitest.max_bits(), Compact::max_value().into());
assert_eq!(Network::Mainnet.max_bits(&ConsensusFork::BitcoinCore), *MAX_BITS_MAINNET);
assert_eq!(Network::Testnet.max_bits(&ConsensusFork::BitcoinCore), *MAX_BITS_TESTNET);
assert_eq!(Network::Regtest.max_bits(&ConsensusFork::BitcoinCore), *MAX_BITS_REGTEST);
assert_eq!(Network::Unitest.max_bits(&ConsensusFork::BitcoinCore), Compact::max_value().into());
}
#[test]
fn test_network_port() {
assert_eq!(Network::Mainnet.port(), 8333);
assert_eq!(Network::Testnet.port(), 18333);
assert_eq!(Network::Regtest.port(), 18444);
assert_eq!(Network::Unitest.port(), 18444);
assert_eq!(Network::Mainnet.port(&ConsensusFork::BitcoinCore), 8333);
assert_eq!(Network::Testnet.port(&ConsensusFork::BitcoinCore), 18333);
assert_eq!(Network::Regtest.port(&ConsensusFork::BitcoinCore), 18444);
assert_eq!(Network::Unitest.port(&ConsensusFork::BitcoinCore), 18444);
}
#[test]

View File

@ -23,4 +23,6 @@ pub struct Config {
pub preferable_services: Services,
/// Internet protocol.
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 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 {
version: version.version(),
nonce: version.nonce(),
state: HandshakeState::SendVersion(write_message(a, version_message(magic, version))),
magic: magic,
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 {
version: version.version(),
nonce: version.nonce(),
state: AcceptHandshakeState::ReceiveVersion {
local_version: Some(version),
future: read_message(a, magic, 0),
future: read_message(a, flags, magic, 0),
},
magic: magic,
min_version: min_version,
flags: flags,
}
}
@ -81,6 +83,7 @@ pub struct Handshake<A> {
version: u32,
nonce: Option<u64>,
min_version: u32,
flags: u32,
}
pub struct AcceptHandshake<A> {
@ -89,6 +92,7 @@ pub struct AcceptHandshake<A> {
version: u32,
nonce: Option<u64>,
min_version: u32,
flags: u32,
}
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 {
HandshakeState::SendVersion(ref mut future) => {
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) => {
let (stream, version) = try_ready!(future.poll());
println!("=== 2: {:?}", version);
let version = match version {
Ok(version) => version,
Err(err) => return Ok((stream, Err(err.into())).into()),
};
if version.version() < self.min_version {
println!("=== 2.1: {} < {}", version.version(), self.min_version);
return Ok((stream, Err(Error::InvalidVersion)).into());
}
if let (Some(self_nonce), Some(nonce)) = (self.nonce, version.nonce()) {
if self_nonce == nonce {
println!("=== 2.2: {} == {}", self_nonce, nonce);
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 } => {
let (stream, _) = try_ready!(future.poll());
println!("=== 3");
let version = version.take().expect("verack must be preceded by version");
HandshakeState::ReceiveVerack {
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 } => {
let (stream, _verack) = try_ready!(future.poll());
println!("=== 4");
let version = version.take().expect("verack must be preceded by version");
let result = HandshakeResult {
@ -310,7 +319,7 @@ mod tests {
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.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, &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.1.unwrap(), expected);
}
@ -361,7 +370,7 @@ mod tests {
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);
}
@ -382,7 +391,7 @@ mod tests {
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);
}
@ -404,7 +413,7 @@ mod tests {
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);
}
}

View File

@ -8,9 +8,9 @@ use message::{Error, MessageHeader, MessageResult, Command};
use bytes::Bytes;
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 {
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 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(), Network::Testnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap(), Err(Error::InvalidMagic));
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(), 0, Network::Testnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap(), Err(Error::InvalidMagic));
}
#[test]
fn test_read_too_short_any_message() {
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]
fn test_read_any_message_with_invalid_checksum() {
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 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 {
reader: read_exact(a, [0u8; 24]),
magic: magic,
flags: flags,
}
}
pub struct ReadHeader<A> {
reader: ReadExact<A, [u8; 24]>,
flags: u32,
magic: Magic,
}
@ -23,7 +25,7 @@ impl<A> Future for ReadHeader<A> where A: AsyncRead {
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
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)))
}
}
@ -46,19 +48,19 @@ mod tests {
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(), Network::Testnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap().1, Err(Error::InvalidMagic));
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(), 0, Network::Testnet.magic(&ConsensusFork::BitcoinCore)).wait().unwrap().1, Err(Error::InvalidMagic));
}
#[test]
fn test_read_header_with_invalid_magic() {
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]
fn test_read_too_short_header() {
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 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 {
ReadMessage {
state: ReadMessageState::ReadHeader {
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> {
state: ReadMessageState<M, A>,
flags: u32,
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 {
ReadMessageState::ReadHeader { version, ref mut future } => {
let (read, header) = try_ready!(future.poll());
println!("=== 10: {:?}", header);
let header = match header {
Ok(header) => header,
Err(err) => return Ok((read, Err(err)).into()),
};
let s: String = header.command.clone().into();
println!("=== 11: {}", s);
if header.command != M::command() {
return Ok((read, Err(Error::InvalidCommand)).into());
}
let future = read_payload(
read, version, header.len as usize, header.checksum,
read, version, self.flags, header.len as usize, header.checksum,
);
ReadMessageState::ReadPayload {
future: future,
@ -78,21 +83,21 @@ mod tests {
fn test_read_message() {
let raw: Bytes = "f9beb4d970696e6700000000000000000800000083c00c765845303b6da97786".into();
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::<Ping, _>(raw.as_ref(), 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(raw.as_ref(), 0, Network::Mainnet.magic(&ConsensusFork::BitcoinCore), 0).wait().unwrap().1, Ok(ping));
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(), 0, Network::Mainnet.magic(&ConsensusFork::BitcoinCore), 0).wait().unwrap().1, Err(Error::InvalidCommand));
}
#[test]
fn test_read_too_short_message() {
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]
fn test_read_message_with_invalid_checksum() {
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 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 {
ReadPayload {
reader: read_exact(a, Bytes::new_with_len(len)),
version: version,
flags: flags,
checksum: checksum,
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> {
reader: ReadExact<A, Bytes>,
version: u32,
flags: u32,
checksum: H32,
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 {
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())
}
}
@ -51,18 +53,18 @@ mod tests {
fn test_read_payload() {
let raw: Bytes = "5845303b6da97786".into();
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]
fn test_read_payload_with_invalid_checksum() {
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]
fn test_read_too_short_payload() {
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> {
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,
address: address,
};

View File

@ -23,7 +23,7 @@ impl Channel {
}
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) {

View File

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

View File

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

View File

@ -58,6 +58,7 @@ impl Connections {
version: connection.version,
version_message: connection.version_message,
magic: connection.magic,
flags: context.serialization_flags(),
};
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> {
self.node_table.read().nodes()
}
pub fn serialization_flags(&self) -> u32 {
self.config.serialization_flags
}
}
pub struct P2P {

View File

@ -34,12 +34,12 @@ impl Protocol for AddrProtocol {
// normal nodes send addr message only after they receive getaddr message
// meanwhile seednodes, surprisingly, send addr message even before they are asked for it
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 addr = Addr::new(entries);
self.context.send_response_inline(&addr);
} 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 {
Addr::V0(_) => {
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());
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);
self.context.send_response_inline(&pong);
} 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() {
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> {
let version = self.context.info().version;
let flags = self.context.info().flags;
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);
}
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);
}
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);
}
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();
trace!("declared response {} for request: {}", id, types::GetHeaders::command());
self.inbound_connection.on_getheaders(message, id);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
Ok(())

View File

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

View File

@ -15,6 +15,9 @@ args:
- bch:
long: bch
help: Use Bitcoin Cash verification rules (BCH).
- zcash:
long: zcash
help: Use ZCash verification rules (ZCH).
- connect:
short: c
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 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;
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::atomic::{AtomicBool, Ordering};
use sync::{create_sync_peers, create_local_sync_node, create_sync_connection_factory, SyncListener};
use network::ConsensusFork;
use primitives::hash::H256;
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;
enum BlockNotifierTask {
@ -88,25 +89,39 @@ pub fn start(cfg: config::Config) -> Result<(), String> {
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 {
threads: cfg.p2p_threads,
inbound_connections: cfg.inbound_connections,
outbound_connections: cfg.outbound_connections,
connection: p2p::NetConfig {
protocol_version: PROTOCOL_VERSION,
protocol_minimum: PROTOCOL_MINIMUM,
protocol_version: match &cfg.consensus.fork {
&ConsensusFork::ZCash => ZCASH_PROTOCOL_VERSION,
_ => PROTOCOL_VERSION,
},
protocol_minimum: match &cfg.consensus.fork {
&ConsensusFork::ZCash => ZCASH_PROTOCOL_MINIMUM,
_ => PROTOCOL_MINIMUM,
},
magic: cfg.consensus.magic(),
local_address: SocketAddr::new("127.0.0.1".parse().unwrap(), cfg.port),
services: cfg.services,
user_agent: cfg.user_agent,
start_height: 0,
relay: true,
serialization_flags: serialization_flags,
},
peers: cfg.connect.map_or_else(|| vec![], |x| vec![x]),
seeds: cfg.seednodes,
node_table_path: nodes_path,
preferable_services: cfg.services,
internet_protocol: cfg.internet_protocol,
serialization_flags: serialization_flags,
};
let sync_peers = create_sync_peers();

View File

@ -4,7 +4,8 @@ use storage;
use message::Services;
use network::{Network, ConsensusParams, ConsensusFork, BitcoinCashConsensusParams};
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 {USER_AGENT, REGTEST_USER_AGENT};
use primitives::hash::H256;
@ -74,7 +75,7 @@ pub fn parse(matches: &clap::ArgMatches) -> Result<Config, String> {
let user_agent_suffix = match consensus.fork {
ConsensusFork::BitcoinCore => "",
ConsensusFork::BitcoinCash(_) => "/UAHF",
ConsensusFork::ZCash => "/ZCash",
ConsensusFork::ZCash => "",
};
let user_agent = match network {
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") {
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") {
Some(s) => Some(match s.parse::<net::SocketAddr>() {
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()),
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") {
Some(s) => vec![s.parse().map_err(|_| "Invalid seednode".to_owned())?],
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::Testnet, &ConsensusFork::BitcoinCash(_)) => bitcoin_cash_testnet_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())?;
edge.reversed()
},
_ => network.default_verification_edge(),
_ => network.default_verification_edge(&consensus.fork),
};
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> {
let old_consensus_fork = db.consensus_fork()?;
let new_consensus_fork = match (matches.is_present("btc"), matches.is_present("bch")) {
(false, false) => match &old_consensus_fork {
let new_consensus_fork = match (matches.is_present("btc"), matches.is_present("bch"), matches.is_present("zcash")) {
(false, false, false) => match &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",
(false, true) => "bch",
_ => return Err("You can only pass single fork argument: --btc, --bch".into()),
(true, false, false) => "btc",
(false, true, false) => "bch",
(false, false, true) => "zcash",
_ => return Err("You can only pass single fork argument: --btc, --bch or --zcash".into()),
};
match &old_consensus_fork {
@ -191,6 +194,7 @@ fn parse_consensus_fork(network: Network, db: &storage::SharedStore, matches: &c
Ok(match new_consensus_fork {
"btc" => ConsensusFork::BitcoinCore,
"bch" => ConsensusFork::BitcoinCash(BitcoinCashConsensusParams::new(network)),
"zcash" => ConsensusFork::ZCash,
_ => 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 PROTOCOL_VERSION: u32 = 70_014;
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 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",
]
}
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> {
// 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) {
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(()),

View File

@ -112,7 +112,7 @@ impl<T> 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> {
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)
.map(|h| h.reversed().into())
.map_err(|e| execution(e))

View File

@ -148,7 +148,7 @@ mod tests {
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(), 0xfcu64.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
];
let mut reader = Reader::new(&buffer);
let mut reader = Reader::new(&buffer, 0);
assert!(!reader.is_finished());
assert_eq!(1u8, reader.read().unwrap());
assert_eq!(2u16, reader.read().unwrap());

View File

@ -2,6 +2,7 @@ extern crate byteorder;
extern crate primitives;
mod compact_integer;
mod flags;
mod impls;
mod list;
mod reader;
@ -9,13 +10,19 @@ mod stream;
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 list::List;
pub use reader::{Reader, Deserializable, deserialize, deserialize_iterator, ReadIterator, Error,
DESERIALIZE_ZCASH,
pub use reader::{Reader, Deserializable, deserialize, deserialize_with_flags, deserialize_iterator,
ReadIterator, Error, DESERIALIZE_ZCASH,
};
pub use stream::{
Stream, Serializable, serialize, serialize_with_flags, serialize_list, serialized_list_size,
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 compact_integer::CompactInteger;
use flags::get_default_flags;
/// Deserialize transaction witness data.
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 {
ReadIterator {
reader: Reader::from_read(buffer),
@ -51,11 +64,11 @@ pub struct Reader<T> {
impl<'a> Reader<&'a [u8]> {
/// 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 {
buffer: buffer,
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 {
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 {
buffer: read,
peeked: None,
flags: 0,
flags: flags,
}
}

View File

@ -3,6 +3,7 @@ use std::io::{self, Write};
use std::borrow::Borrow;
use compact_integer::CompactInteger;
use bytes::Bytes;
use flags::get_default_flags;
/// Serialize transaction witness data.
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 fn serialize<T>(t: &T) -> Bytes where T: Serializable{
let mut stream = Stream::default();
let mut stream = Stream::new();
stream.append(t);
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> {
let mut stream = Stream::default();
let mut stream = Stream::new();
stream.append_list(t);
stream.out()
}
@ -55,21 +56,26 @@ pub trait Serializable {
}
/// Stream used for serialization of Bitcoin structures
#[derive(Default)]
pub struct Stream {
buffer: Vec<u8>,
flags: u32,
}
impl Default for Stream {
fn default() -> Self {
Self::new()
}
}
impl Stream {
/// New stream
pub fn new() -> Self {
Stream { buffer: Vec::new(), flags: 0 }
Stream { buffer: Vec::new(), flags: get_default_flags() }
}
/// Create stream with given flags,
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?

View File

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

View File

@ -293,7 +293,7 @@ mod tests {
// real world message
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
let address: Bytes = "BA99435B59DEBDBB5E207C0B33FF55752DBC5EFF".parse().unwrap();

View File

@ -38,7 +38,7 @@ impl BackwardsCompatibleChainVerifier {
let current_time = ::time::get_time().sec as u32;
// 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()?;
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
let current_time = ::time::get_time().sec as u32;
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()
}

View File

@ -1,6 +1,6 @@
use rayon::prelude::{IntoParallelRefIterator, IndexedParallelIterator, ParallelIterator};
use chain::IndexedBlock;
use network::Network;
use network::ConsensusParams;
use error::Error;
use verify_block::BlockVerifier;
use verify_header::HeaderVerifier;
@ -13,11 +13,11 @@ pub struct 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());
ChainVerifier {
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(),
}
}

View File

@ -1,6 +1,6 @@
use primitives::compact::Compact;
use chain::IndexedBlockHeader;
use network::Network;
use network::ConsensusParams;
use work::is_valid_proof_of_work;
use error::Error;
use constants::BLOCK_MAX_FUTURE;
@ -11,9 +11,9 @@ pub struct 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 {
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),
}
}
@ -31,10 +31,10 @@ pub struct HeaderProofOfWork<'a> {
}
impl<'a> HeaderProofOfWork<'a> {
fn new(header: &'a IndexedBlockHeader, network: Network) -> Self {
fn new(header: &'a IndexedBlockHeader, consensus: &ConsensusParams) -> Self {
HeaderProofOfWork {
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
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 {
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 {
return work_required_testnet(parent_hash, time, height, store, Network::Testnet)
return work_required_testnet(parent_hash, time, height, store, consensus)
}
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");
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 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 {
return max_bits;
}
@ -152,7 +152,7 @@ pub fn block_reward_satoshi(block_height: u32) -> u64 {
mod tests {
use primitives::hash::H256;
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};
fn is_valid_pow(max: Compact, bits: u32, hash: &'static str) -> bool {
@ -163,14 +163,14 @@ mod tests {
#[test]
fn test_is_valid_proof_of_work() {
// 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
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
assert!(is_valid_pow(Network::Regtest.max_bits().into(), 0x181bc330u32, "00000000000000001bc330000000000000000000000000000000000000000000"));
assert!(!is_valid_pow(Network::Regtest.max_bits().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, "00000000000000001bc330000000000000000000000000000000000000000000"));
assert!(!is_valid_pow(Network::Regtest.max_bits(&ConsensusFork::BitcoinCore).into(), 0x181bc330u32, "00000000000000001bc330000000000000000000000000000000000000000001"));
assert!(!is_valid_pow(Network::Regtest.max_bits(&ConsensusFork::BitcoinCore).into(), 0x181bc330u32, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
}
#[test]

View File

@ -24,7 +24,7 @@ pub fn work_required_bitcoin_cash(parent_header: IndexedBlockHeader, time: u32,
}
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 {
@ -140,7 +140,7 @@ fn work_required_bitcoin_cash_adjusted(parent_header: IndexedBlockHeader, time:
// Special difficulty rule for testnet:
// If the new block's timestamp is more than 2 * 10 minutes then allow
// 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 {
let max_time_gap = parent_header.raw.time + DOUBLE_SPACING_SECONDS;
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.
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 {
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 mut header_provider = MemoryBlockHeaderProvider::default();