Commits on Source (11)
......@@ -61,7 +61,7 @@ name = "base64"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
......@@ -69,7 +69,7 @@ dependencies = [
name = "bencher"
version = "0.1.0"
dependencies = [
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"chain 0.1.0",
"db 0.1.0",
"network 0.1.0",
......@@ -85,7 +85,7 @@ name = "bigint"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -121,9 +121,19 @@ name = "bitflags"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "blake2-rfc"
version = "0.2.18"
source = "git+https://github.com/gtank/blake2-rfc.git?branch=persona#c7c458429c429b81fea845421f5ab859710fa8af"
dependencies = [
"arrayvec 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "byteorder"
version = "1.1.0"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
......@@ -131,7 +141,7 @@ name = "bytes"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
......@@ -181,6 +191,11 @@ dependencies = [
"yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "constant_time_eq"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "crossbeam-deque"
version = "0.2.0"
......@@ -262,7 +277,7 @@ name = "domain"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -629,7 +644,7 @@ name = "message"
version = "0.1.0"
dependencies = [
"bitcrypto 0.1.0",
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"chain 0.1.0",
"network 0.1.0",
"primitives 0.1.0",
......@@ -650,7 +665,7 @@ name = "miner"
version = "0.1.0"
dependencies = [
"bitcrypto 0.1.0",
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"chain 0.1.0",
"db 0.1.0",
"heapsize 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -698,7 +713,7 @@ name = "murmur3"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
......@@ -720,6 +735,8 @@ dependencies = [
"chain 0.1.0",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"primitives 0.1.0",
"rustc-hex 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serialization 0.1.0",
]
[[package]]
......@@ -864,6 +881,7 @@ dependencies = [
"primitives 0.1.0",
"rpc 0.1.0",
"script 0.1.0",
"serialization 0.1.0",
"storage 0.1.0",
"sync 0.1.0",
"verification 0.1.0",
......@@ -879,7 +897,7 @@ name = "primitives"
version = "0.1.0"
dependencies = [
"bigint 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-hex 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
......@@ -1145,8 +1163,9 @@ dependencies = [
name = "serialization"
version = "0.1.0"
dependencies = [
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"primitives 0.1.0",
"rustc-hex 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
......@@ -1241,7 +1260,7 @@ version = "0.1.0"
dependencies = [
"bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitcrypto 0.1.0",
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"chain 0.1.0",
"db 0.1.0",
"futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -1441,6 +1460,8 @@ name = "verification"
version = "0.1.0"
dependencies = [
"bitcrypto 0.1.0",
"blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc.git?branch=persona)",
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"chain 0.1.0",
"db 0.1.0",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -1448,6 +1469,7 @@ dependencies = [
"network 0.1.0",
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"primitives 0.1.0",
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"script 0.1.0",
"serialization 0.1.0",
......@@ -1536,12 +1558,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
"checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d"
"checksum blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc.git?branch=persona)" = "<none>"
"checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9"
"checksum bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d828f97b58cc5de3e40c421d0cf2132d6b2da4ee0e11b8632fa838f0f9333ad6"
"checksum cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719"
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
"checksum chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c20ebe0b2b08b0aeddba49c609fe7957ba2e33449882cb186a180bc60682fa9"
"checksum clap 2.27.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1b8c532887f1a292d17de05ae858a8fe50a301e196f9ef0ddb7ccd0d1d00f180"
"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3"
"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150"
"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
......
......@@ -26,14 +26,13 @@ import = { path = "import" }
logs = { path = "logs" }
rpc = { path = "rpc" }
primitives = { path = "primitives" }
serialization = { path = "serialization" }
[profile.dev]
debug = true
panic = 'abort'
[profile.release]
debug = true
panic = 'abort'
[profile.test]
debug = true
......
......@@ -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,31 @@ mod tests {
assert_eq!(block.merkle_root(), merkle_root);
assert_eq!(block.hash(), hash);
}
#[test]
fn zcash_blocks_are_parsed() {
let blocks = vec![
(
"040000000000000000000000000000000000000000000000000000000000000000000000db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac4000000000000000000000000000000000000000000000000000000000000000090041358ffff071f5712000000000000000000000000000000000000000000000000000000000000fd4005000a889f00854b8665cd555f4656f68179d31ccadc1b1f7fb0952726313b16941da348284d67add4686121d4e3d930160c1348d8191c25f12b267a6a9c131b5031cbf8af1f79c9d513076a216ec87ed045fa966e01214ed83ca02dc1797270a454720d3206ac7d931a0a680c5c5e099057592570ca9bdf6058343958b31901fce1a15a4f38fd347750912e14004c73dfe588b903b6c03166582eeaf30529b14072a7b3079e3a684601b9b3024054201f7440b0ee9eb1a7120ff43f713735494aa27b1f8bab60d7f398bca14f6abb2adbf29b04099121438a7974b078a11635b594e9170f1086140b4173822dd697894483e1c6b4e8b8dcd5cb12ca4903bc61e108871d4d915a9093c18ac9b02b6716ce1013ca2c1174e319c1a570215bc9ab5f7564765f7be20524dc3fdf8aa356fd94d445e05ab165ad8bb4a0db096c097618c81098f91443c719416d39837af6de85015dca0de89462b1d8386758b2cf8a99e00953b308032ae44c35e05eb71842922eb69797f68813b59caf266cb6c213569ae3280505421a7e3a0a37fdf8e2ea354fc5422816655394a9454bac542a9298f176e211020d63dee6852c40de02267e2fc9d5e1ff2ad9309506f02a1a71a0501b16d0d36f70cdfd8de78116c0c506ee0b8ddfdeb561acadf31746b5a9dd32c21930884397fb1682164cb565cc14e089d66635a32618f7eb05fe05082b8a3fae620571660a6b89886eac53dec109d7cbb6930ca698a168f301a950be152da1be2b9e07516995e20baceebecb5579d7cdbc16d09f3a50cb3c7dffe33f26686d4ff3f8946ee6475e98cf7b3cf9062b6966e838f865ff3de5fb064a37a21da7bb8dfd2501a29e184f207caaba364f36f2329a77515dcb710e29ffbf73e2bbd773fab1f9a6b005567affff605c132e4e4dd69f36bd201005458cfbd2c658701eb2a700251cefd886b1e674ae816d3f719bac64be649c172ba27a4fd55947d95d53ba4cbc73de97b8af5ed4840b659370c556e7376457f51e5ebb66018849923db82c1c9a819f173cccdb8f3324b239609a300018d0fb094adf5bd7cbb3834c69e6d0b3798065c525b20f040e965e1a161af78ff7561cd874f5f1b75aa0bc77f720589e1b810f831eac5073e6dd46d00a2793f70f7427f0f798f2f53a67e615e65d356e66fe40609a958a05edb4c175bcc383ea0530e67ddbe479a898943c6e3074c6fcc252d6014de3a3d292b03f0d88d312fe221be7be7e3c59d07fa0f2f4029e364f1f355c5d01fa53770d0cd76d82bf7e60f6903bc1beb772e6fde4a70be51d9c7e03c8d6d8dfb361a234ba47c470fe630820bbd920715621b9fbedb49fcee165ead0875e6c2b1af16f50b5d6140cc981122fcbcf7c5a4e3772b3661b628e08380abc545957e59f634705b1bbde2f0b4e055a5ec5676d859be77e20962b645e051a880fddb0180b4555789e1f9344a436a84dc5579e2553f1e5fb0a599c137be36cabbed0319831fea3fddf94ddc7971e4bcf02cdc93294a9aab3e3b13e3b058235b4f4ec06ba4ceaa49d675b4ba80716f3bc6976b1fbf9c8bf1f3e3a4dc1cd83ef9cf816667fb94f1e923ff63fef072e6a19321e4812f96cb0ffa864da50ad74deb76917a336f31dce03ed5f0303aad5e6a83634f9fcc371096f8288b8f02ddded5ff1bb9d49331e4a84dbe1543164438fde9ad71dab024779dcdde0b6602b5ae0a6265c14b94edd83b37403f4b78fcd2ed555b596402c28ee81d87a909c4e8722b30c71ecdd861b05f61f8b1231795c76adba2fdefa451b283a5d527955b9f3de1b9828e7b2e74123dd47062ddcc09b05e7fa13cb2212a6fdbc65d7e852cec463ec6fd929f5b8483cf3052113b13dac91b69f49d1b7d1aec01c4a68e41ce1570101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff071f0104455a6361736830623963346565663862376363343137656535303031653335303039383462366665613335363833613763616331343161303433633432303634383335643334ffffffff010000000000000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000",
Some("00040fe8ec8471911baa1db1266ea15dd06b4a8a5c453883c000b031973dce08"),
),
(
"04000000679f938245c093c578992dc92d89b6519fd4e0fa3e7c3197c25f2db918000000bc70dfd69dc4fcb8309f4dab2bcf949f059b5466dbd008c434db7aefe45dfd0800000000000000000000000000000000000000000000000000000000000000003cfa13585d21201d5a00000000000000b756f2ff51d793dedb786012000000000000000000000000fd40050019901da314f9faea65a09bc19ca1b6a6da7ad0c9475bc30792d68fcb1056486ec0d4078a38ca920a6b098ab1a5879c5a5199ad176e4bc46a9375427eb0861237aca940948bd5a950133ccbde0d46791cbbe9760aa62e4f2a8af972ec4df4a2fbceb70987e439f3cc15eac0ce6e4ba0bd1ff2171acf44ca0dff7e712c1e0f00bb6faa58d014ede732baecb0704e071d3333ff2d75d46c13ccfdd270483536c0b82aa97ef7d32ffb0121d0828853d3435992e17c09312d60fd9957a97f391a168b88e5bc9bb5d764d38676b64eb0a2167d2e0793db495e2a8141712528c665f997ea61233912321fb06286980e498901464736085f16e70a827dd1010a166c79596120d5157ce44b47b036a6152b7343ce0a1b3ec7d00ac4bb8551221ee33eff062e4d9d1feb14874612ebd27f48c5c3b297e7d493121092312d5d3e2cebd9c420f961885f262a13537b7a26abb2cbf70039f24c9c420ce26884e156ec5c2c29b201dcad7e12b58513fbe1a25f13e84523727532520249b8efa302485fda5cc3f39e56e0352f576a93957a571420532a9f625d9fd400e8a1c6d5b54afe2675c5538ea354013a4717e278ec0be1bff3696026c519992e32270d067d163aa5583bb938995335f37f941d1b22293f6b239bf3b55e51938fe0c4d46cf4375c11b92d2efe3e32499beec6ccd2f9c7b125ad696c6d9ba0d41eeaa8007352c455ef1ca3fc8fa15d536ccf1edbb5da2a2d08980c4dba8df5b1e6f692b5a8e0dea526b51b30fd037bbb6968d3f3cf04662502a3540db3afb9be88941e6864fb01d33192f19d95d980657996820a5748140ca34f883ce650e9fc04d2133533f21d48343e0c440cc2e10b1e35295deb8894070b461fc90afb6bb4b50d77538ea21734d34813e2152a94185c8d3deb004a199fff04a49d1b8bd19828346bfb69fe2bccd7bd7900fe47e41192d92adbbad16ba8ed07dd180537ca0b3388a4b0136416614ff0d4b792bfcf652f16f49c021053323630670b5f605ed75ccfd601031bd0fb2d5f178af612e08b188a8478f1f2a76c1cd951df3092d60a3ceb325ba9fb3f893a41f852c95e6d04037330e10ce82fd22a54040909b7f4aa77df295536b81487341dcde28965adb713b5ab165c4cbac83a934836f578328fde0ab46cbe8f8f83b359539ad521737fb904970199122e6589f14f5b7c7525a03f7e7f27791d4d02334924b984647ad528a343e496cb98514f757e3733054ae2542834896fe8b960f7f4f6ac857cebd88a340a309cba1853c4c7a6ce729896f9e5ed64dfdaba760d1fcafc6c080059acba817b9e8d271cec071021b45ec19f89e5a0b7273a7147dfdfdff406ee421db3f31c8bce7c5ef10db58abe1465277dfdad4c8e38c06038ba354b3ada7f7d122504ccdfb0b0498820bfed69016d29c46c41988e94109043b59b29e34fcd9febc1094374ec451b2705dd55623bc2eb266f7e4b5f19a60adcceda5348398f162400b2d6317c1257f638424121da8ce3ee0d8346f2b432e10ca342994abd119c4602aa55ffa8040f286669f4bde83877568506db20540bf05db234511969f4c9246f87279bd2362475df510629b73e3918a4ffa784e31a3a6ea96113b1fad9bd0c896c48e846cfd9a302f1950c19c219081cf4552601b02463f71834413c228135ae8e6440cfad1bb81e1e5bb71845119532a937e74efcef086273ae9d3a8e055122a56693ef8ef5a527a4d474ef9e93431abed00e3a3fef3996c302cbb8333abf6542695ff8d0279903a15d23b217d988fdd387405af33e5a96d3990198115f4bf35ea94be177a1baf4d96142a736951ad99707c44d0d5453f91949c0b8a558ccb68e63701d357c2b748790006faab993e4f696154c8aa1dc373373000801000000010000000000000000000000000000000000000000000000000000000000000000ffffffff100296020cff740000000000002f4e614effffffff025022fa01000000001976a9140461c2fa917ecaa5d2e54bba0d473b3b151b86e788ac38447e000000000017a9147d46a730d31f97b1930d3368a967c309bd4d136a870000000002000000063883b157d2ab07b367ce1a9add40fb4e2dba32742849ea270c7395c0e770ac8f00000000484730440220746ce7a84b0ca935f29d0fda7ee48e525d29aa5ca360be89bb62f196bdfe68580220014fc14583af2c2cf558cc753656b25c757d9416bd6fa6a0cebb26212c0f9a5601ffffffff78d67f7191f82431a856749aa6ba658b68f3185b661e2954a8dd95fadab0bddf00000000484730440220251808888063949932bdda0202dbc9bad9803a453ddd27b23054dca802dd5a400220487d85e8fe34b23aac101bd194cddc5eddae2e47961246e03515170ad7c8029f01ffffffff9b965c55c427662b7d3f2cf56639bda6a0585814609d12f7f06612310daa0a9d00000000484730440220223673361878eb7341d6bb6be69832eb910279bb96e59f0997636fb6def950b70220220c0bf4bd94a025e710a14ceb668a4a84baf6abd411a13db0eab596eb02ce6201ffffffffa5a2be29c0a6ce749100926e6c1cdef768a52c072b9514f964454f2f0eec5df40000000048473044022027f9379455f61ee83fb01f6c8fb72e6cccc0dcdf1c9435d6373cc9a0d2a82989022049b738d30f39d641e69c9bd994f257bcf810477e274209765d5d8c076b5e1b3d01ffffffffe2e373cb1ca90590db4a65d57b58ff9206a4f80b7efda6df0db50d503270e9b20000000049483045022100b49a5a5eea79d4564af854accbb890c4cd46fdae7195338ecd5a3485488f802302203d63d14edc80644b2362219fcd5edf06964839dba8014b73daa600c4c9e51e2e01fffffffff9544be0006ae232a1948b6ea52c182dcc7c708494b57496c55b732be840d8c2000000004847304402203107275b242f80a81b97815cb0394e20680ffd9883e6ac9fb0b9a6b999d5964e022010d586cc6bd017f7dd6b6dd671b5ea1d7bca16992ddea505674b79d5a1649afd01ffffffff0000000000010000c4090000000000000000000000008eba0eded9d3fbc39454096392eb72d2049b1b5152d2483bebb99469f9ec7d23070ebbaf17e32e54ab8fbc5fc6d41c1e888bd12164aa9d28955698b636bcb4866c075efcd9e2fed85ae5cceaba14146e82a415f2bb07fea622a8a2e3a3beac5f8f795b999cb902711ab062b1ac056c3b930815f4a08717e7a314ed834bea1bd9c9adf2dfff7dc85bc6d6ce942fdd6e2e98b5a5c201c91bac71bdeddcf5462415c67fd65b65151dca3917a67ce1f3be7904286a8b997f251a4749ca1ae9a0ef5df11b62896337d72ae53169d301837d459160687afb920cd7ac049da2d8656191ebb6eee05898819f1ce1b5b27125b6c328c8afb1cb39e3e8ca64e08c8b7118fddfef46ce03f11b129c1060493d63c83d42f894ddb4742317293689e07cb2677f032c6056b48df364827a6060786ccc6cc0b6e2f654f2c3bada6438805fe2d7b7ee030e852ed357e50d0d4647c9dc8f5d56e57952860ff176d5ff9d711cfda33102de0b0917d8d2d2d33dcb400196eca36898e1e87587b217aa23c6fb46cf504eb1e506a99c3cc54f7291e07cb9490cbb1bbc8a88afb50f772ad7631e147a4cafc5d5e002157a786a7bfd4df7708b3cb019ff838a6b11be4562323adae65700514428cbb602267f3a3af3b89d736039fe567cb85e36c2b270e61338dcc583d7776207b2a138021e9a4393e93a739e15e4869871c5416cacb7f0191c43f0163da28527c6defae50309b1fce63dd0f57e5a80188a0bb6df0f2e146fde2bd746d421cbb77ab3ea2bbf022dd6dc7c321a3d401b8065c098fb619de8be1ea5f9de74d4f651535915b31e88c0a386398be9d105e30de961218086430985f870b3418e51011dbe95686772f77962434e8eb3ab4a5c1480df0ec118e4c7daa699d6efed1beaed79a3e1d090542b4cf589ad326a4eaa82423fc5765d877ff8449c81ad658ed33a17ce646845e75256f4c7ff9b9f7ad6218160e21fb47680b08cb768d9467083d975bef4e1dde0c0f2ed0590c9e8b77381ee306be9f0bde301d2b305a332fb821fc5e13461d50e8e7c944e63c0955ee8ede46c0ed00e5f0b2d0f9ff5737c4fc2e6610b63d3699e6e5da0bb0322105fd723c409637f516ec1812e4daeeaa6be9be76f0c437d85db33b68d234f2e9f5408f9469727d55ec4c72fda791b27fd9b34ff92a368c30d30b4eff7b028bb30e79331afc121c6216c390f5be16904fd48d71a81b1d60d1784364e36abbfd9640d9025edfcb30a36191848468a5675ac0ff1f51093e580def56d3c50cf75b67a84d49f18bf4671d9ea714ed5703526bbfe9c3919a1c695eb01ec4babe128594133479ae110983e3881bbd4624611aa2edc45b28d358607edba145a6773f6d991be58961b7e2f96055380d5731f17fc7953a80a7b817824033eb6a89e01eac7b69b21024f0eb94584d45dc6a108c55106a21e856f874671e1cbb8b33889b127b65bdb3730cc1e2dc25a4838ebb6f510a3e7ce5ec32d0e7020a905bd8bb01c62b44eaeaee7fbca069fb9b939402b9ab49636a40617af2fb078eab5dc2628013ce57efa48b9a409ca5cd004527ed6482a3c39988241ca7355a90b65d4c3e824e7a1500a80f46386f23c92cd708be19e1d26aa8001b50402042e89ff88066e56aa1247c8f0b6a832c25d343473e641fcffd444ec9d793bacd00a16dc0659d43fbf6b427da2c4a4be32dde7a173d1a0e68712640a0ec87ed69141260e76ae7f8cbb21e18f8fed249a3f39971ac0c3ad6c84c9922c627c45c1b2a20bc054e16fa7650dc2f92f697008df6575fd2c2d42d4a9395f6c9ee9ec46cf30cc2b44947b9132d5b459fe37edfee2d68c016ef9c65dcbc91956203e39e24c6316eb69a3aca5eb72721710967c836f6f52284f0ae06f1f07f130b94d4f669aa154e7288d818c08684ddfc62f2ec3ffb06cc680be71fee54a3cfbb9e8d8008394fb6736edb04e4c35d48def959acb1ddceb2f337861dea667961e046827b2fa79a9cb69fb74af1332e21a3fc2fc7238200b674bb96fe750de1b653344e1565024d928d75f00d44a6a908c909f6910007cb6258cc3131f06f9c883a332a9f59a4ef8f5d5bff2415f227ee69058677047298b844403259abf3f5bb3eb04cbd099aeadc3b303b960732b39afc61e6ec531758d50659a70e05fc6ef81d03098851b7c44e8938b0fc06cc9af56ce23da29b07d1c427bbdb463b46e5f3dfc8bee9ba1455d669602f83ff980a6c3a43b42c5a23927c621204de9e9e2b5a664273da9863f6c7ca9fde20e2cf34de3a276d398926e64a87f94fd6e0c4b08edfe9d46d26af3d8c250d14f03d1bef0654528f79c6e06790e35309a216125e0aa998db1ebeab28e821056c007564fa3bb5eb179b4b3b26306749387e2d6d257df50ac3ead5fee62ad0c4724dadf0eae7baefbef17a69e0a492109ac14d94ef2f0d2f69c6111fba41bad54decbc5485b1865f2d5b04547e9e2466cbdf6ba413d3ae823fb7d1fdedf0c74e5753b9793122d1e0fb35b4d7c5ec46ec0ffec60dfe781494426541a1ae597e29802464a447ae3db5007c293cd032a658995c85f49d796df45cfb0c9934c4d6692e0c3dae8d3ee64590e3086e558c0228906fcf6f4e469119b36f816181c8a2de1fa96b818d5173b38812667c0b3820e02000000000134dd0e00000000001976a9145b851089e40a899a839412926ae77abe4be3fd8688ac0000000001000000000000000044040f00000000008eba0eded9d3fbc39454096392eb72d2049b1b5152d2483bebb99469f9ec7d2349dc04f6700aa1f67d574077b5e34127636477de7434242bf296d1f3935875f9b72a3e09e554474c6451090f6648c9fd43f398561bc55259a42e8f156389747d215247df247163814fad59ec45350befdff54bb9c709e6d6e6083a68c01c39eb421d412baa70ebc7a3b9e4f792cdd388047b7d20a0a386e6239f7f1999d0ca92dcd2a6e69e04091bafeae86e1fb137e0afeb2e21d45c970dd48df2ef11730b3702f671ba55cff64a9c0c584ca1350e17c773079018f71334003ab14a6c2a8d470b627753e2901107e387ce3cd7049857d7d5f1cd54c7a56e5e98216c3a5fb3b00d0ff4c3b733a956b6cb5cf463117f0b7df083a82f361ddcb41ab602e0be4529032dc70609f2da2044a8582d2f56fe50356fe6a4d3c2962c6c398d7bf69df1c27a0319730e9d5c0e224957ecbe1deb3a299df3c792cc5529fcd12fc9bd72e614a5f60a06e3bcd46db8cb891a4bb2561d568e4c3eb5e178ad2176f87eae5496a561cdcdf243d682baddd93bd5cfe68e3e68715fba99a937d591c2d7049cc0fd680e3bf30202bbf5c44f49a3bb9326df32763559584541c0c0bdb0bfbf93b87b84bf323cd8021fcb54b8fbc9c615f962fc80cd60b61f7887e7f44b196b4acffc27566ad0f2ce032e1b7e456c0e9cb2e7aa30ac07209df56c29a594798a95b918552e0a864c747b0224889997602301106ab83e15e1d214f109e341b0385f193e9d14504a6c3b14fe02055ed289f932d312ad134941b31c305ae78fd55482e1869527aa0358b9385fe2c888eecf079932c96a1185b42d6d533eade2fe67e83ef58d4a75d3e80b91c89a0d18ba6b412b3858e1503db302e918b36d2074c13b34ad32b657de1b4e3b37beba3bcff3a6908e2c70da7c93b469ce84e6d285896652fe9c47de1004f82fecd830e90981e92a80249e2aed2db63283789f1a0effad193d6bd9f4d5406f8dd724c1e4e666dc1fa452a5ad1fec0b8c90ecbf1eb935513af85546bba841aa67d3bf920dc174b4a3c3b45e65834c76db69289914376ffb4caea8326b0598ac08765346f763d5031b3951e1b457402ebbdad039bee104815dbfb4da5c828ea242f0751696f9667e39c5cfb909101e4456976fca96c9ec57743cf5a3a31e68648bd9c7a30aaffb5492e22db950006a45d9d5ac4cb438742240335eeb681087901aed0358459910fe856720f5e3702fbb8352fd6c305573ef54e199f12e63e1c0018e9bfbda591adf96a3e1c920ef71f5421e14dbb3bc623e553d68f3afec3cd44cbe4a8dd51b2552942b2519b59ba0d7258bb40d15390f14ec070eabbd24bd09157c882e46d46dd76c675e8bae61c98a204aee5afb7e401cca4a5413a40b21e01b742bbe1c800489c97b8dbe4bd187d39752a0747de0bf80e7a138ec20843d596d7c7d634b41ac5f1380b3647b67c2040b125c6db7347ec41c68bffed98faa24a8d71a3439f83c1594ca7a3eaf352ce9f30655f8a5af8e96ecd5bb9ee68a9d720635775693e2f7a3845fb1847610b0f84891f3af6cd04796676f59bd514cbf41340f427967d415dfbdf1eeb4c381730ff1c34d2459350c91a36a1846d473021bdf654b265e5fac39ab313bf568a9dc2c315245f88ac1e81c472f82853f0c51a69839fdb2d67fc678e92a5f76e6ae934b33c03b4c37a0f2b48cf1b1119861dae53d293b3c1f58d1603106b87521b8f8d2d0d899e0c9842ffd7223d58a063ede765442e189aa7c35dd8ed2f71d9f06e41d4384da83471745fdc23767a82a7b0de2c9f53539233ab73150e0c9c0d7564891fdfbd6d0fd44ae3062408d5f297a369ef0607a01ff3626bb2b64c60b951816ad3fe61fac01dd79c112609a50c000c3f76c70b128f9dbc38b3d76435e88bf43a4b1d0c1a5fcef4a1c0f146d7d541d2dcb080b983eb9bf55960b3376df44514e66fa1f220d5b4451736efc6c8744fdf5013a0681be6f5437bc464cf45277d60d5e130eaf01e932804c4104a052df21fca16d675982464ea2b31ab994cf33879eb3f60123cea5650dfe7fac5b24533104e382e91fb1460ec5dabb101e56a87d505e69fb25a17665b7d86248daf4c7d2a11bf717bcc9c8869eec936dd0c630ba0be24d41410176d4a213025dacffc18526384256e902c1ba30dc0005572022e2d4838149a14a6abf27e0e30776aa3abad399f79a9bf4a7c7dfc5b01e68d5027f36b86f8206efa3108434f2ed82b2eb42c946ef9dbfe14869a72b3539d9184e8eb93a6e2256322402ebbae2b2bc914fd84ef7a2fbc1587c18b15a9b8a23f98af219f089bf8b73eb7f34dc8b9e38b8bc1610975c53c5fad2772b005e185ca85c4a5849e9564eb63f1897ca3c32731797129e310271a4c97f3bdb1f371aa967d8c1431097739f82190642575155c721273203548c3365e12c7c252aaa552dd43ff59b359025b574b7ef7bfbba4000e917aa24b6953a59aa663c4f670d95b061170f4a0efae3084c2267a6e1b82daf1ff9e2070bc8896bd3f0d2282f667f21bd27aa815e11b6298b84fdd3e0935f3bade86f16255dd1dcb73e1fed21605b8e6b4b489494cad3dd1bdd579643d911571a101851ffd25c0729a3584840bea3da442003813f83db91950f020000000001c0c0a501000000001976a914a558cdedcba064c1c4add31b939a53453cff641e88ac00000000010000000000000000d0e7a501000000008eba0eded9d3fbc39454096392eb72d2049b1b5152d2483bebb99469f9ec7d232f45126f308379c0cd568a34b8dcec81583fca4812962c53cd9578f34a67364720b38e209bbeb4fd92c58ed6aff6d864271c7ff80704c5271767d2c0abef7cc2de65af8fda1dc15153b45f2e6aefc0f950dea324284d8d1349d7c2b6b9dd59fc0fa7ca044fd863ba45256aa79c8e8dbb44fbc85c11f9b47dcc57ea5f46edc6bd73cee881582afb6f9db67502d1555e56110ed20698f1b1db83a6f9907b46ff2cec9f2fdb59f6816fb5823abef0cd9629c711cf026af7d35281af56512a2e57a6b5cf359b0a7a951dbb16b1d030b6e610e431c2c47d9cf7d966c8c889d9bc14ff93a570868398233012d06ccf85ad0fa96ca83695a6fb1d4ed0c92d4a96c9fc9e032c4b75e4a84acc1f88d4b375beed100321452876b4c2e2e0986851e85540160203147f3481c5ec52598e22145496c25a72d79698fb96364d5d34fb97845eeb56880b0429287d77cde12d308f7ab4f35c4c41ee40285142807c78d40dc25a9ceeaf4b18f9fda0673823f4cf49236f3fb6b22c9331d45e9e799c7a32dc9a9eb16f7c6c0302e04f9753368b9ac568eae8798cf3b39aa7d0e2df4f6a6cdb8c7f43b620cb1b032ac13cea0bb5e6097bc34f15ec1b1c9049274504227d0ba664d713c34acf868f0220fa6e287636a7b337368a8b0fe45e869e8ccf295792d16b98c6adf9ee774222030fad77937ec91b9c3133ae84e7ea41b9369129e4d0ea550739bfe1f5a44732f80329495036524c58ac8dde3326cc1beb5add777805f7b12dfa1eac2f8c4129b69a215ebfee57c2ba2fe733d4b0fd13b996d8f00408a8037f9ec2e4674e98963ff2e370c1cd2ae1bd816cd46856bbb9870b7641b33c2eddd251eb29c8e6e8972dbf40327e62649dafdf34927dc8d718f46bf54e222561067b0e77e8ed529639ca12c115571d754cddf6d7c06fc0dea4ddda4fd0f26dc3e8a0bec124c9179dbc08ee839e73f9fe7218027da396e835c9fbda8bfcba8c5e5fdb402bef182b151f18313b8b7ad46511e678e411de2eb402c90a13753e7f3c5fef11846d5bdbcd5575d099019cb8660c8a333199f5ad7f8b740f26dffe289b25b124468846b61e957b96e25c2eb45c449e68aa4ff9cae7149903c9cdb24c174f13c43c1ef93c0e0f98bbfad0dc0a10f66469cf12454b0949325f67b0101be538f566162ccc6d11beba9d99b9f0b8bd1f354eec10a5b593d83cbd6713d40212b17b700cde46f4d658e31db3f1e4aa98b2f571a4e72f1426c6c637179de1a9b6a837b5a3e918bcaf536957a4b3d070a8f3c73d8b361c6024a127ecfb285df18da8377b9ded7c4ad96b121311762ff61f9217d3ca35ff1999747ac0be8178a30ccee35728c8af7dab6516a8e1cc1004da95c85a36b0f76d734ba1ff52c8159ecaa6d1d6168a9d6b69e60361f6a3799edd84c86beff76c3dd1b716c5b7ac08412a4ecb4259be758ce4c9deedb43b6c2af96b84f15117e3ee925cf71e626daa3513b1ecac09702a0a3e64e3f43ba77557fccd96a8506f9b69de6a51a42bb03dd3507141c4829394b1cb6d6827eab3964662070efbd8543e14a0ad0100bdd257fcbb26f0e13360e4b671d38cdddd622088da5234e1c3f8fe9456ca74a633712b422866cc9cc51c1a251778ef4136a2393a798ab10a4576c5eff3a53a612f1adee3cbed308cdf5797694a4cf1e685ea81c2c146302a171889072338dffe271de3a49b3278bf739ca17b5f808fa3ccb98bfdb2cf7566543687f23dadc89436083cee8536af5dc563c4dd9f64941eca9a1173f346e3e8d135772c967421ef4798573b596de80bc47ceb8695d36f8d8c9bc7e7ac5d808ec6b1b49a2bbcda8a702263b3ee73c5e8ef7854f7387c9e0894e9e8c2d053d88fb7f6d6efa59979585b9f97bee642b026b77fe892445761fe42bae187a1a8d4f42a21fdedda684015950f2dcd35bc9066c8a1da10036a928d396156b6fada400c98a835022e58c768fb81f57e6fee2d2ff86119e6ea23addbf3a1ce6205921edd678c0c6801ff8649df6f4e732940c81d2976989c5f3edde611b0a18e3379ddb48db8d3228c60197f0303aff81e31ea262197ace5a4146c995330569d9ab807145ed28dccb5bd78bff950c1573ca6ed0f255b9e5cf1d9915e2ffa6276afe9c6bed23106e40804a3b517c3d8022a72b1404480c52b65407e6a0828f19b168a9dd0483ca1b9a68824c245afa6054fb2e3f2ece47387c546ade707cb704f22a50759201ed9c1acbed766aff4244de908d3b5b4c991df8affec17aa2d7511ac8aad77e77e07d664fab1b00f00776dcf31275b7a084feee2a8fd1d4f166b8ddc58f1ced9318d763920d313a335a92d4550adbba4c93cbf2efca2ceff1c7666fd219901729eb6cfcbfbf83e223b837832b83b2b4ca56a74ba988c27467590961bee0543bc5019a48df2960d1341a38c6924209f94ab20653024407e1aefd143bf1bee806bb54b333986caab2af2b34016a835a4999a413e7ed6d1178d51daa07615ce858aecdc6211ad3016a6103e0dc4ac184da231ef95451651e81ee05bad446012a1cbbd605c2a690e0fade46e44dfc8051ebbc50db0d656f8fe5a2eefef059fa61aeb911016f3bbd0f25c070200000000045a7a0400000000001976a9144edb2834648584f796fc059bb428b0fe8f27f6b288ac177c0100000000001976a9145f92d6d7295fae53cd54ba5af555d34cf2673e4788ac573e0500000000001976a9144996071966b09ba41cfea9c3659e14168757b71988ac0c170c00000000001976a9145e7641b17d94dadf996856912729ef61acc6a98588ac00000000010000000000000000e472170000000000e2db0653b37fe149f71da01e797e5a9b571bad4d2b247dfe2f281c0fd3cb91fc1ff1cebd18c935664b95ee9b221b23ac0905dcf67e15b5f5e979bd9fa1d60a2900e127b590bbe23caf576a40b6a115d503ab128ccc8c98cf577d01398e6c59affbcbe75888663ac847c4e2add9514b278f11d9dc2dc6d78a897fcbc8e5157cf8a2639b34f61e67d5c76d13978810dbb58bf460cbde47973b1eda74b017bdad7c8c09b530cddfd6fda47a84bb0e95db0b315804d47d59233ddb434a251c346b2df5effbb99ac1ad7faa22189111f3ca3797cd3c5e2b7a4a94ae2843748e94a812a58266abba285b6736b5fcc2ceb57dc5c355e8ac127355314e15c8dcff6264d5c8b0dfbbddb25872c3fe60fce8c9d5672caa11d801015378eb86ca274e1c1c98030584ea6fee7fdaf3e30b8a94aa556c1efd193335ae54f6cb3582dd2c74be66ef032d2d6146296085be4d162ce040b01b867a1bedf9e0b687d789b6dd159ad97f0c0a032f20af54b65c0c9a75c36bbdad1ed7b64fe38af5ec391c846eb5ee49927cdabb5f95fa390d8a5f19f80b1d159ba887fb9a662aa3b8555a2be64758cab2bd450211166bd4e7f1ca7c3b576890a55c6e0c0bbed4e98b4a41e6a2f02eca42bde826030632045b3dacec64802287ac26bdeb0e4e8fbe38a245c13d84ff96b5bb04ce60030e6941405a8e42009b4911c3895fe33293abc89006095930fda14b4cc34dc5e2022370e0bf10cf346c050490b5bd42dbf6dc3f1413d372878b840695d57f5a3cd4031138d1a4b67f400722153d2e9b0c0318083d4230ae1df529e83c93bf3075b5a3f1ba20623bcee1a28f226eb9a8debfd21a28cd42ace11a53d9794c45a6576f40b91b6520882755b5cabb926b607119acbfeb2aeba8aa965ddc78f9e0d490ab5bdffe38ab9f2ce139a5d0ad07e23f77ea958af5be3c8904ac884c6c25bb67c0f2522a3f6e01adb1a875958e07b6d3cdec9e47db444783b9dfa4ecaf7cc85ce18a93100a65ac062edeab8e500c5ce4ef677bc4951264e8beb31e4e676653d26b012567a1d52c60ff968e7d7286affeabe726f8479a5e9f20fe02af860c9e05a4554d6eb90a96fea2175014bd58992fc9c7cd60d58240359384c93025fa55ee9999f40582bd95e6d96a532af9bdabfe0e3539a6596b34df10cfd7ee24d07599288ee6c9ae95c55fd6d82e994c2f522ef389475d060d91400e2de52e0b045c874adf2e4a719233a60d52a8f683e1f648d7d382aad6169352305b37a347eb00b16e6456f773cfe11c5b617b5bf85542fe7348a7105aab9711b2a2cb228006d8e9ea49ce3d1bbb597107dfca1f96cd3faf1b8ef96990f098163bc5d30dd133f193d98479d80ffb48dfad23809e2096f246e2cf5d83d61b1314f0268103ed76bd5f4fc0b0fab50c7c8a1061e76cd838ad9dfb880939b6fbecea53d18779ae55f1c8930507c71738ff5145b0c6d08614c09fc82a5adc70f9d1df59bf54c1b288a33ca6efe42c8e9b6895b84019f174a46604af6f68268b43d33dbc179fa3d775752e0788b3f179541ccb64d7087cfd17257ac8732bc0d7d75ee91843fe92bb4057cafa3e3a731f3501eace8e066a783636c7d94b5892167888a57cea5be9d1dc4d37b6aed81ad588eefc650ecd3ca743b975b6f54b5154b8278d99b1a2ab2d8201f6682a1716d51ecfe128dee00e37f4a74439a054aee4ed20ae7ea0bf5e216e7519d7f7f81813c1709c15d44c233ca7912c561de867f18bda9a0c9bb0ff590c53f69a1853d5151116d288bcbdb455c53472d91c07d7071da8bda78efbd645875249223b502f2efec5886796d7c50b4086574e3e51f943a0f86b60e2606f7c7df9b88e88121f9162beea81a73f2f7855121ea32601bdd8eec0c8919f79565e4ae2eb1cef56e9c66a33584abbedfd72f374119c9d98440c237b28f53d8a6f971b7224654da279d754e5a070d585759f7923c6b7f115c18d4886adb87cebbd0ed6c7c2bcc13647ad1dd9c076113febfefb561992464a324435014b1f413221d137efeef4e092a8adffc31c2ab2188242948e23a81714f3993e2dd4aa10b0f21bdee84e3a8913098b2b2e23197884cd395eb2a893c6baf08b159c097ea82db9559f16c8b3036f06b63fd38032f32fdb0b4dc1418c81a1d67ec1cc35244661d6170982507abb33759a9b7fb8525ad57327b2a68207f8474f805024ab88230a508b8e56caf660a7572a9fd4a0b5477208f28e6598dd0483a7b92f36fce0f311508eed33dada7ae9464d3bb41fda6a7531f1647fc3a65b7a119d6b2962edf5aa785e17b942a33359fb6c8bf823b6422b4d93903d1f0f606de2e62522065d76be1e33374be7cf3a45afadc4d62044d1760111d734d01a0b0099f16fb727912d60119a57605e9e2289421a1c9f63ac17dd0cba0c344253403d96b67a50d103e5679ab986c802a58eacec012a2de947d58c9db9fed2bdda2be15d2cfc74385229a8a480f5d96d92aa61951312860b87d160c3eaa1c3f627554f037081d82d64da05f431fa5711993509741db3474967418fa2ed2f4718d580f948db9eade71dd518ed8076e3f5bbee897c37b57c276c07386e47aeb1bd3ca767d0c1dac94bd9376cbc847a950410d7ecb06cb301e27112674d510a98337eb62108020000000005288e0100000000001976a914d493ca02bad4bf42e86a4ae312b12491a68c050c88ac6fef0300000000001976a914150298650c9cdce6e9b60e1f2cf5bad79faa228c88ac4a102e00000000001976a9143dfb86b14ec006f19a402be53ad2566be4d8eae688ac360f4100000000001976a914556cdd84e20cc381fa74401b258be423bab28bb688acc6c00100000000001976a91467afcd5ee007060dba426b247834b782a205eb4988ac00000000010000000000000000ed847600000000008eba0eded9d3fbc39454096392eb72d2049b1b5152d2483bebb99469f9ec7d236e13068caf617b3d717717ef6d1bc5d98324f4a69a44562914dcbfa6893adc0a010e1a86c7ab474c35078b1b914057a42bbfd1f0224e34d6b1403c19672c1ad0ca8ee08740f281333cbbfd556836db83f11df4ab507cae431fd28222713bdeec7ec63852198d1f071d92ccaff8fa797fc2de0970c03011d3c50957ab8f67d51d6a7990e505e9a56db4980b632610aaed8db2c8f1553ac8fa133bb56cc9dadc27c0fb5f62b7d3036b1e0aa1027fe52e37926ebd88646dccbd8dcd69ac0b83d4c285360b8dee3d2c9fd47e0776d7692719b4fa0268531f06627ce02518e6097e5a9c186bdc0aaa1178428a3ab9f07d587236fe56fc20ce07b52a7847d6c37b968c022c166041405e88140e5e0762e4d08338a044af7e9e1ee52b37df6878f9afb40902207575ccf54a1731a3de23ca8c9b510de2f3c123eeed946a2ef2e82fd8978cb80b037c89ead5aebe4a0a844d228072ecc70b904b9cab51984dec6abd6c568d10661b78de78fc076fff013bf305a15b76168ffb50db577314ffd2f63690f45b04d102116562e53178fbfd1e5c8257120a74e04a7b1b90aaba492202f18084f7a78c930223906feb30fb5d64b28e0850dfc6908744685c8e81b257cd45945deb570d02e3031d7f713617137c53eead6e203ebcbca7b9c675d862c78a415c031ebf2192cea502168e0021c818f2e828d2d43b379bf89e8c95584257d447cb83824bc784321a43032c9ed9ab04fcd2879dffc15bfbab5c29ca84c438aed46b29021112fe354c555fbaa32b4e4a801a12ce8a92e85f7bd3b4b9d7496d8a71b81761b3312789c94d587e27c34dd0129768a4fff3848b7ced97e901a9028f8c373e5bf338aa31b57b5db97625603cd1a7b0e2aadbc61a4495ab0e286cfde09d44e8a509a98b414d8dda1c58b9cee8aeed2172924bcfae750ddf84983d7997d10a168648c0123c72d876dbf8c2c6919a9ee5f8ad88fa054fb1f47615f93abcf3dc3d027a6711be5f716ecfa5482fb1dedfb8cc83f6eb97f2d865348222472da0e5889327b65b6cb9917ff77775ffdd4318b5a51a4d968c119f793628da7a855b76c004dca69ec36ebff4af72f7043a85c3bddab0bc02c7fbf42ef8fb0f8a821dbba3b03ab935458ccd8cd2aff84f3789172067167256ac97b1c08727a263c256a05866e99c08b694bfbd33bf9651ed76e86c69d2c937fb8bd2ba596a86caa7f82962dc41cb8a27477d7b429aff7bc3d7a9ff4b4d14200aa98f8e7fc9830ed585a182436848ede0ba69cbcdc783245ae478add12c4cae7e610b44a0ccb08f101d67f9dba9629522ab8a742850a08142b0af323e691687bfbf0b9652f70b1fbc94c90f33cd56256b1c3e68e0b1533bc9950a4148a50f2c066010a0e5dec1402d6676145bdd5ace28d25ee3fef3baa2ff50b3bfcde4567fbcaddcf23d4ddaf2da9c699e9db0bab33be5fcdd134c66934928d3bc607dad82c9993c7980ff17f21d830d147346af16af02f3ce9e2a8f669f1d4ea21ccc5ceee86bba789b68e311c354d6160b327433af497915baa803a48126776e07c9d3346d5ef912b2aea67d79fb203110279d3a47d13cec3e6a0b950bdd051a7e3bc405b2c9eee664d7540312d2a47844e577b094f7547ef399f2f854080742504d8d3f9d20658225d5abed295c963ce7e8acd8b8b8355ebe75888066beb7e1077841e86caba180b559400d6ba40ddfb86d14a8174b498b7211219a5255bce09dd1b549466462112c86a3efe10f2b3969e50d270b4379265c2a2fada4db801f328db8baf63b925dd0ca7e8fa15a2e4cccaecd953d340910b393e8320382c13080d87a42aa9ff35b0516e87b0ee67f286be920bfb8331ff95c9dafd9de4f2b22fca55bcf60158467ee412a82e79a89eff7fa102f16c05a3657993dde480e999c5831764128b62920f791629e13be16fcaa45587463b1f7b527f38493cb931ad778f46f7bd62c639656931ea611d3bb8d7a94c7edb652618b3bf87edcf70d7c3a0956d29c65d804588de41801606e34ef8bcaf654b26ea7c93ac5e222ac016e2a22bc62abd5f1872a2d0f058d793bf6dea24f8e499a091feda528bc59e5ef3670dfa2debcbee903aab22adac5c27badb63ef9da0db1548c3959a65aac37e738c7c4491869749e356302069d3688a35d7f36a3402353774832be02bac7de714a7cfd00278275c5bbbfd416ddbf2284c809941f0d1284b647312dc1d13064c060e14d78d9bc172401c0781a4df277e921f75a49855b071a89899ad97d71ad96adc332aaf5616faba941e36b954ceb198833e5cc2a0d35c7ffe709422baf264e43a20faa0d81fa44078a61d20136aa227e4bf0e770046282c9acbb5f9c37d7c1a6ea8aca4272b3066eec825ca8dab51aef98fd7fbaba379ba7785683c4afbb8978a184cdb8376dcea5aa841de1cc01773db7f355ad63fe090d0b0d01ee4629ae5b40f3a24d47b552bb8b07f7efd9ae87a56d372fe33cfdc91856247514d02c3ca0e74fb342cb8d8ce50cd2b6acff6845237e7e740ceaa4ed721d28cd2f70fc73f835f49322226668b700c68190bf21fc353bd2b13803a5f1393a0ea3d2715f20b870950682cd9bfc7850ef0d0100000002671971f9811ac48c028985598cecc5b1f9e23f0343044de34d7041cd7a7cf224150000006a473044022055b593994aa9b91cfce8730f0544a5d6308ad2662a25a1a0bdb3952beb994212022061c521cc3b1520be7593b5c1a7a61eb77f0652a4558c525e96ede4d929b065dc01210394b97dd9a40bc0f4538f08e929b3c893093c33a77e659b041717b519d5f23010feffffff52034dff2767dcb83a0fb43e06870b52cc412bd4df536800b332d6f6b86dc1f6100000006b483045022100ddaa0b651bad108c092bb65b90b3747c49b6949d65bf3f32cdc5d70787dc896b022023dbbc16c01fc8b626c7791c8b8595dda1947ed48668fb5ae46da8cf1e35a8de012102eabfe9998e30efa5dab428d74962541018fea99544a6a6a92679d0fb5e839395feffffff04219f0200000000001976a914a9ef780ecfca888a02d2c0f57c8348bc79ff9be888ac29301300000000001976a9142e36bae95bd35592d7de514709b42cee784d79c588acc0353600000000001976a914792a4caf8f801d9cceb43025190a753160a649b088ac51430f00000000001976a914443bed0dea39225274bf8303dee96b12a7f801eb88ac8b020000010000000424b473664bca164a7f29fb2b4fcd50aff256ebb5e4c8f6650497969e9fe5d503030000006b483045022100ad863266c4344cc06d7873a2c9735142d7c47aeb6f095d72ecdbb280b909b0610220754ab1ebfb7a44b8c0f6ea3244f0d5eeca8f13173e8efa02b6ee9f9418125723012102c0ceb5f481380b54b6a5a896725151b947976a2035b2a36cb9662b9e57a01272feffffff69607fe8d0ec8ea8694d8d60182c7f7e58a43c2070d90722a72b621176fe3e56010000006b483045022100f11afacab1db34339802d18236d1690204b317345aad3457ec582232640f004202207b64083875de6d689d5f3019df04c3a4ab7109db982e1e28db218c5435aeb6df012103ab7a86f1726712eacace15cab56a76bb942f325ae23cf797ba4ac24362237c79feffffffbb09f8be8dff323406963d11b7e67e03617e85461c737c477b1300463a01e04e000000006a47304402201950ea50216297fe99345957f5c3a20b161fe01b3f6e3337593a9339a1d29068022019facca870cb378367f44d5921fe1b5d4630f7f93faf882004beafee7800350e0121034665f76c297843efaf29eeccce5462d7fd6aaf1d9e1b5d8c2b95503da2cec628feffffff4931d2192433eac801adbfd4182fd9ad17a007f7b77ff8e45f31c018d195161d000000006b483045022100b625b04f8dd0ffe12f6833bac472b7c0e8b12b51f61799627a138b8399928455022047bdd821aab60d9a1983708d0182d05d4c68fa5410d821034305a582ef25a5520121032b657c31338d33d82a632ec11358f0ac06b7cff08c711d8b00de16cdf6bddb45feffffff0205ed1d00000000001976a914b0cd5132da67c76dcf6b57ff3f8247ee1e3eeb0e88ac30440f00000000001976a9143ab7919e60c9e78d082cf41fd9812121b0f4e7ca88ac8b020000",
None,
)
];
set_default_flags(SERIALIZE_ZCASH);
for (origin_block, origin_block_hash) in blocks {
let origin_block = origin_block.from_hex().unwrap();
let parsed: Block = deserialize_with_flags(&origin_block as &[u8], DESERIALIZE_ZCASH).unwrap();
let serialized = serialize_with_flags(&parsed, SERIALIZE_ZCASH).take();
assert_eq!(origin_block, serialized);
if let Some(origin_block_hash) = origin_block_hash.map(H256::from_reversed_str) {
let parsed_hash = parsed.hash();
assert_eq!(origin_block_hash, parsed_hash);
}
}
}
}
use std::io;
use std::fmt;
use hex::FromHex;
use hex::{ToHex, FromHex};
use ser::{deserialize, serialize};
use crypto::dhash256;
use compact::Compact;
use hash::H256;
use primitives::bytes::Bytes;
use ser::{Error, Serializable, Deserializable, Stream, Reader};
#[derive(PartialEq, Clone, Serializable, Deserializable)]
#[derive(Debug, PartialEq, Default, Clone)]
pub struct EquihashSolution(pub Vec<u8>); // TODO: len = 1344
#[derive(PartialEq, Clone)]
pub struct BlockHeader {
pub version: u32,
pub previous_header_hash: H256,
pub merkle_root_hash: H256,
pub time: u32,
pub bits: Compact,
pub nonce: u32,
pub nonce: BlockHeaderNonce,
pub hash_final_sapling_root: Option<H256>,
pub equihash_solution: Option<EquihashSolution>,
}
#[derive(Debug, PartialEq, Clone)]
pub enum BlockHeaderNonce {
U32(u32),
H256(H256),
}
impl From<u32> for BlockHeaderNonce {
fn from(nonce: u32) -> Self {
BlockHeaderNonce::U32(nonce)
}
}
impl BlockHeader {
pub fn hash(&self) -> H256 {
dhash256(&serialize(self))
}
pub fn equihash_input(&self) -> Bytes {
let mut stream = Stream::new();
stream
.append(&self.version)
.append(&self.previous_header_hash)
.append(&self.merkle_root_hash);
if let Some(hash_final_sapling_root) = self.hash_final_sapling_root.as_ref() {
stream.append(hash_final_sapling_root);
}
stream
.append(&self.time)
.append(&self.bits);
match self.nonce {
BlockHeaderNonce::U32(ref v) => stream.append(v),
BlockHeaderNonce::H256(ref v) => stream.append(v),
};
stream.out()
}
}
impl fmt::Debug for BlockHeader {
......@@ -27,9 +70,11 @@ impl fmt::Debug for BlockHeader {
.field("version", &self.version)
.field("previous_header_hash", &self.previous_header_hash.reversed())
.field("merkle_root_hash", &self.merkle_root_hash.reversed())
.field("hash_final_sapling_root", &self.hash_final_sapling_root)
.field("time", &self.time)
.field("bits", &self.bits)
.field("nonce", &self.nonce)
.field("equihash_solution", &self.equihash_solution.as_ref().map(|s| s.0.to_hex::<String>()))
.finish()
}
}
......@@ -40,6 +85,72 @@ impl From<&'static str> for BlockHeader {
}
}
impl Serializable for BlockHeader {
fn serialize(&self, stream: &mut Stream) {
stream
.append(&self.version)
.append(&self.previous_header_hash)
.append(&self.merkle_root_hash);
if let Some(hash_final_sapling_root) = self.hash_final_sapling_root.as_ref() {
stream.append(hash_final_sapling_root);
}
stream
.append(&self.time)
.append(&self.bits);
match self.nonce {
BlockHeaderNonce::U32(ref v) => stream.append(v),
BlockHeaderNonce::H256(ref v) => stream.append(v),
};
if let Some(ref equihash_solution) = self.equihash_solution {
stream.append_list(&equihash_solution.0);
}
}
}
impl Deserializable for BlockHeader {
fn deserialize<T>(reader: &mut Reader<T>) -> Result<Self, Error> where Self: Sized, T: io::Read {
let is_zcash_format = reader.is_zcash_reader();
let version = reader.read()?;
let previous_header_hash = reader.read()?;
let merkle_root_hash = reader.read()?;
// TODO: rename to transaction format - original, witness, zcash, must be enum, not flags
let hash_final_sapling_root = if is_zcash_format {
Some(reader.read()?)
} else {
None
};
let time = reader.read()?;
let bits = reader.read()?;
let nonce = match is_zcash_format {
true => BlockHeaderNonce::H256(reader.read()?),
false => BlockHeaderNonce::U32(reader.read()?),
};
let equihash_solution = if is_zcash_format {
Some(EquihashSolution(reader.read_list()?))
} else {
None
};
Ok(BlockHeader {
version,
previous_header_hash,
merkle_root_hash,
hash_final_sapling_root,
time,
bits,
nonce,
equihash_solution,
})
}
}
#[cfg(test)]
mod tests {
use ser::{Reader, Error as ReaderError, Stream};
......@@ -53,10 +164,11 @@ mod tests {
merkle_root_hash: [3; 32].into(),
time: 4,
bits: 5.into(),
nonce: 6,
nonce: 6.into(),
equihash_solution: None,
};
let mut stream = Stream::default();
let mut stream = Stream::new();
stream.append(&block_header);
let expected = vec![
......@@ -82,7 +194,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,
......@@ -90,7 +202,8 @@ mod tests {
merkle_root_hash: [3; 32].into(),
time: 4,
bits: 5.into(),
nonce: 6,
nonce: 6.into(),
equihash_solution: None,
};
assert_eq!(expected, reader.read().unwrap());
......
use std::io;
use hex::{ToHex, FromHex};
use hash::{H256, H512};
use ser::{Error, Serializable, Deserializable, Stream, Reader, FixedArray_H256_2,
FixedArray_u8_296, FixedArray_u8_601_2};
#[derive(Debug, PartialEq, Default, Clone)]
pub struct JointSplit {
pub descriptions: Vec<JointSplitDescription>,
pub pubkey: H256,
pub sig: H512,
}
#[derive(Debug, PartialEq, Default, Clone, Serializable, Deserializable)]
pub struct JointSplitDescription {
pub value_pub_old: u64,
pub value_pub_new: u64,
pub anchor: H256,
pub nullifiers: FixedArray_H256_2,
pub commitments: FixedArray_H256_2,
pub ephemeral_key: H256,
pub random_seed: H256,
pub macs: FixedArray_H256_2,
pub zkproof: FixedArray_u8_296,
pub ciphertexts: FixedArray_u8_601_2,
}
pub fn serialize_joint_split(stream: &mut Stream, joint_split: &Option<JointSplit>) {
if let &Some(ref joint_split) = joint_split {
stream.append_list(&joint_split.descriptions)
.append(&joint_split.pubkey)
.append(&joint_split.sig);
}
}
pub fn deserialize_joint_split<T>(reader: &mut Reader<T>) -> Result<Option<JointSplit>, Error> where T: io::Read {
let descriptions: Vec<JointSplitDescription> = reader.read_list()?;
if descriptions.is_empty() {
return Ok(None);
}
let pubkey = reader.read()?;
let sig = reader.read()?;
Ok(Some(JointSplit {
descriptions,
pubkey,
sig,
}))
}
......@@ -10,6 +10,7 @@ pub mod constants;
mod block;
mod block_header;
mod join_split;
mod merkle_root;
mod transaction;
......@@ -26,7 +27,8 @@ pub trait RepresentH256 {
pub use primitives::{hash, bytes, bigint, compact};
pub use block::Block;
pub use block_header::BlockHeader;
pub use block_header::{BlockHeader, BlockHeaderNonce};
pub use join_split::{JointSplit, JointSplitDescription};
pub use merkle_root::{merkle_root, merkle_node_hash};
pub use transaction::{Transaction, TransactionInput, TransactionOutput, OutPoint};
......
......@@ -9,6 +9,7 @@ use ser::{deserialize, serialize, serialize_with_flags, SERIALIZE_TRANSACTION_WI
use crypto::dhash256;
use hash::H256;
use constants::{SEQUENCE_FINAL, LOCKTIME_THRESHOLD};
use join_split::{JointSplit, deserialize_joint_split, serialize_joint_split};
use ser::{Error, Serializable, Deserializable, Stream, Reader};
/// Must be zero.
......@@ -96,6 +97,7 @@ pub struct Transaction {
pub inputs: Vec<TransactionInput>,
pub outputs: Vec<TransactionOutput>,
pub lock_time: u32,
pub joint_split: Option<JointSplit>,
}
impl From<&'static str> for Transaction {
......@@ -205,6 +207,16 @@ impl Deserializable for TransactionInput {
impl Serializable for Transaction {
fn serialize(&self, stream: &mut Stream) {
if stream.is_zcash_stream() {
stream
.append(&self.version)
.append_list(&self.inputs)
.append_list(&self.outputs)
.append(&self.lock_time);
serialize_joint_split(stream, &self.joint_split);
return;
}
let include_transaction_witness = stream.include_transaction_witness() && self.has_witness();
match include_transaction_witness {
false => stream
......@@ -232,7 +244,8 @@ impl Deserializable for Transaction {
fn deserialize<T>(reader: &mut Reader<T>) -> Result<Self, Error> where Self: Sized, T: io::Read {
let version = reader.read()?;
let mut inputs: Vec<TransactionInput> = reader.read_list()?;
let read_witness = if inputs.is_empty() {
// TODO: default flags must be: ZCASH, WITNESS, ...
let read_witness = if inputs.is_empty() && !reader.is_zcash_reader() {
let witness_flag: u8 = reader.read()?;
if witness_flag != WITNESS_FLAG {
return Err(Error::MalformedData);
......@@ -249,12 +262,19 @@ impl Deserializable for Transaction {
input.script_witness = reader.read_list()?;
}
}
let lock_time = reader.read()?;
let joint_split = if version >= 2 && reader.is_zcash_reader() {
deserialize_joint_split(reader)?
} else {
None
};
Ok(Transaction {
version: version,
inputs: inputs,
outputs: outputs,
lock_time: reader.read()?,
lock_time: lock_time,
joint_split: joint_split,
})
}
}
......@@ -332,6 +352,7 @@ mod tests {
script_pubkey: "76a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac".into(),
}],
lock_time: 0x00000011,
joint_split: None,
};
assert_eq!(actual, expected);
}
......
......@@ -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)),
......
......@@ -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());
}
}
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;
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,
}
}
......
......@@ -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,
}
}
......
......@@ -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());
}
}
......@@ -161,6 +161,7 @@ mod tests {
script_pubkey: script_pubkey,
}],
lock_time: 0,
joint_split: None,
};
P2shCoinbaseTransactionBuilder {
......
......@@ -7,3 +7,5 @@ authors = ["debris <[email protected]>"]
lazy_static = "1.0"
chain = { path = "../chain" }
primitives = { path = "../primitives" }
serialization = { path = "../serialization" }
rustc-hex = "2"
......@@ -46,6 +46,15 @@ pub struct BitcoinCashConsensusParams {
pub magnetic_anomaly_time: u32,
}
#[derive(Debug, Clone)]
/// ZCash consensus parameters.
pub struct ZCashConsensusParams {
pub pow_averaging_window: u32,
pub pow_max_adjust_down: u32,
pub pow_max_adjust_up: u32,
pub pow_target_spacing: u32,
}
#[derive(Debug, Clone)]
/// Concurrent consensus rule forks.
pub enum ConsensusFork {
......@@ -58,6 +67,8 @@ pub enum ConsensusFork {
/// UAHF Technical Specification - https://github.com/Bitcoin-UAHF/spec/blob/master/uahf-technical-spec.md
/// BUIP-HF Digest for replay protected signature verification across hard forks - https://github.com/Bitcoin-UAHF/spec/blob/master/replay-protected-sighash.md
BitcoinCash(BitcoinCashConsensusParams),
/// ZCash.
ZCash(ZCashConsensusParams),
}
#[derive(Debug, Clone, Copy)]
......@@ -76,10 +87,22 @@ impl ConsensusParams {
match network {
Network::Mainnet | Network::Other(_) => ConsensusParams {
network: network,
bip16_time: 1333238400, // Apr 1 2012
bip34_height: 227931, // 000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8
bip65_height: 388381, // 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0
bip66_height: 363725, // 00000000000000000379eaa19dce8c9b722d46ae6a57c2f1a988119488b50931
bip16_time: match fork {
ConsensusFork::ZCash(_) => 0,
_ => 1333238400, // Apr 1 2012
},
bip34_height: match fork {
ConsensusFork::ZCash(_) => 1,
_ => 227931, // 000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8
},
bip65_height: match fork {
ConsensusFork::ZCash(_) => 0,
_ => 388381, // 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0
},
bip66_height: match fork {
ConsensusFork::ZCash(_) => 0,
_ => 363725, // 00000000000000000379eaa19dce8c9b722d46ae6a57c2f1a988119488b50931
},
segwit_deployment: match fork {
ConsensusFork::BitcoinCore => Some(Deployment {
name: "segwit",
......@@ -88,7 +111,7 @@ impl ConsensusParams {
timeout: 1510704000,
activation: Some(481824),
}),
ConsensusFork::BitcoinCash(_) => None,
ConsensusFork::BitcoinCash(_) | ConsensusFork::ZCash(_) => None,
},
fork: fork,
rule_change_activation_threshold: 1916, // 95%
......@@ -103,10 +126,22 @@ impl ConsensusParams {
},
Network::Testnet => ConsensusParams {
network: network,
bip16_time: 1333238400, // Apr 1 2012
bip34_height: 21111, // 0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8
bip65_height: 581885, // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6
bip66_height: 330776, // 000000002104c8c45e99a8853285a3b592602a3ccde2b832481da85e9e4ba182
bip16_time: match fork {
ConsensusFork::ZCash(_) => 0,
_ => 1333238400, // Apr 1 2012
},
bip34_height: match fork {
ConsensusFork::ZCash(_) => 1,
_ => 21111, // 0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8
},
bip65_height: match fork {
ConsensusFork::ZCash(_) => 0,
_ => 581885, // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6
},
bip66_height: match fork {
ConsensusFork::ZCash(_) => 0,
_ => 330776, // 000000002104c8c45e99a8853285a3b592602a3ccde2b832481da85e9e4ba182
},
segwit_deployment: match fork {
ConsensusFork::BitcoinCore => Some(Deployment {
name: "segwit",
......@@ -115,7 +150,7 @@ impl ConsensusParams {
timeout: 1493596800,
activation: Some(834624),
}),
ConsensusFork::BitcoinCash(_) => None,
ConsensusFork::BitcoinCash(_) | ConsensusFork::ZCash(_) => None,
},
fork: fork,
rule_change_activation_threshold: 1512, // 75%
......@@ -130,10 +165,22 @@ impl ConsensusParams {
},
Network::Regtest | Network::Unitest => ConsensusParams {
network: network,
bip16_time: 1333238400, // Apr 1 2012
bip34_height: 100000000, // not activated on regtest
bip65_height: 1351,
bip66_height: 1251, // used only in rpc tests
bip16_time: match fork {
ConsensusFork::ZCash(_) => 0,
_ => 1333238400, // Apr 1 2012
},
bip34_height: match fork {
ConsensusFork::ZCash(_) => 1,
_ => 100000000, // not activated on regtest
},
bip65_height: match fork {
ConsensusFork::ZCash(_) => 0,
_ => 1351,
},
bip66_height: match fork {
ConsensusFork::ZCash(_) => 0,
_ => 1251, // used only in rpc tests
},
segwit_deployment: match fork {
ConsensusFork::BitcoinCore => Some(Deployment {
name: "segwit",
......@@ -142,7 +189,7 @@ impl ConsensusParams {
timeout: ::std::u32::MAX,
activation: None,
}),
ConsensusFork::BitcoinCash(_) => None,
ConsensusFork::BitcoinCash(_) | ConsensusFork::ZCash(_) => None,
},
fork: fork,
rule_change_activation_threshold: 108, // 75%
......@@ -172,7 +219,7 @@ impl ConsensusParams {
match self.fork {
// SegWit is not supported in (our?) regtests
ConsensusFork::BitcoinCore if self.network != Network::Regtest => true,
ConsensusFork::BitcoinCore | ConsensusFork::BitcoinCash(_) => false,
ConsensusFork::BitcoinCore | ConsensusFork::BitcoinCash(_) | ConsensusFork::ZCash(_) => false,
}
}
}
......@@ -197,6 +244,7 @@ impl ConsensusFork {
match *self {
ConsensusFork::BitcoinCore => 0,
ConsensusFork::BitcoinCash(ref fork) => fork.height,
ConsensusFork::ZCash(_) => 0,
}
}
......@@ -218,6 +266,7 @@ impl ConsensusFork {
// size of first fork block must be larger than 1MB
ConsensusFork::BitcoinCash(ref fork) if height == fork.height => 1_000_001,
ConsensusFork::BitcoinCore | ConsensusFork::BitcoinCash(_) => 0,
ConsensusFork::ZCash(_) => 0,
}
}
......@@ -226,6 +275,7 @@ impl ConsensusFork {
ConsensusFork::BitcoinCash(ref fork) if median_time_past >= fork.monolith_time => 32_000_000,
ConsensusFork::BitcoinCash(ref fork) if height >= fork.height => 8_000_000,
ConsensusFork::BitcoinCore | ConsensusFork::BitcoinCash(_) => 1_000_000,
ConsensusFork::ZCash(_) => 2_000_000,
}
}
......@@ -234,13 +284,13 @@ impl ConsensusFork {
// according to REQ-5: max_block_sigops = 20000 * ceil((max(blocksize_bytes, 1000000) / 1000000))
ConsensusFork::BitcoinCash(ref fork) if height >= fork.height =>
20_000 * (1 + (block_size - 1) / 1_000_000),
ConsensusFork::BitcoinCore | ConsensusFork::BitcoinCash(_) => 20_000,
ConsensusFork::BitcoinCore | ConsensusFork::BitcoinCash(_) | ConsensusFork::ZCash(_) => 20_000,
}
}
pub fn max_block_sigops_cost(&self, height: u32, block_size: usize) -> usize {
match *self {
ConsensusFork::BitcoinCash(_) =>
ConsensusFork::BitcoinCash(_) | ConsensusFork::ZCash(_) =>
self.max_block_sigops(height, block_size) * Self::witness_scale_factor(),
ConsensusFork::BitcoinCore =>
80_000,
......@@ -249,7 +299,7 @@ impl ConsensusFork {
pub fn max_block_weight(&self, _height: u32) -> usize {
match *self {
ConsensusFork::BitcoinCore =>
ConsensusFork::BitcoinCore | ConsensusFork::ZCash(_) =>
4_000_000,
ConsensusFork::BitcoinCash(_) =>
unreachable!("BitcoinCash has no SegWit; weight is only checked with SegWit activated; qed"),
......@@ -290,6 +340,43 @@ impl BitcoinCashConsensusParams {
}
}
impl ZCashConsensusParams {
pub fn new(network: Network) -> Self {
match network {
Network::Mainnet | Network::Other(_) => ZCashConsensusParams {
pow_averaging_window: 17,
pow_max_adjust_down: 32,
pow_max_adjust_up: 16,
pow_target_spacing: (2.5 * 60.0) as u32,
},
Network::Testnet => ZCashConsensusParams {
pow_averaging_window: 17,
pow_max_adjust_down: 32,
pow_max_adjust_up: 16,
pow_target_spacing: (2.5 * 60.0) as u32,
},
Network::Regtest | Network::Unitest => ZCashConsensusParams {
pow_averaging_window: 17,
pow_max_adjust_down: 0,
pow_max_adjust_up: 0,
pow_target_spacing: (2.5 * 60.0) as u32,
},
}
}
pub fn averaging_window_timespan(&self) -> u32 {
self.pow_averaging_window * self.pow_target_spacing
}
pub fn min_actual_timespan(&self) -> u32 {
(self.averaging_window_timespan() * (100 - self.pow_max_adjust_up)) / 100
}
pub fn max_actual_timespan(&self) -> u32 {
(self.averaging_window_timespan() * (100 + self.pow_max_adjust_down)) / 100
}
}
#[cfg(test)]
mod tests {
use super::super::Network;
......
......@@ -3,6 +3,8 @@ extern crate lazy_static;
extern crate chain;
extern crate primitives;
extern crate serialization;
extern crate rustc_hex as hex;
mod consensus;
mod deployments;
......@@ -10,6 +12,6 @@ mod network;
pub use primitives::{hash, compact};
pub use consensus::{ConsensusParams, ConsensusFork, BitcoinCashConsensusParams, TransactionOrdering};
pub use consensus::{ConsensusParams, ConsensusFork, BitcoinCashConsensusParams, ZCashConsensusParams, TransactionOrdering};
pub use deployments::Deployment;
pub use network::{Magic, Network};
......@@ -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,34 @@ 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 hex::FromHex;
let origin = "040000000000000000000000000000000000000000000000000000000000000000000000db4d7a85b768123f1dff1d4c4cece70083b2d27e117b4ac2e31d087988a5eac4000000000000000000000000000000000000000000000000000000000000000090041358ffff071f5712000000000000000000000000000000000000000000000000000000000000fd4005000a889f00854b8665cd555f4656f68179d31ccadc1b1f7fb0952726313b16941da348284d67add4686121d4e3d930160c1348d8191c25f12b267a6a9c131b5031cbf8af1f79c9d513076a216ec87ed045fa966e01214ed83ca02dc1797270a454720d3206ac7d931a0a680c5c5e099057592570ca9bdf6058343958b31901fce1a15a4f38fd347750912e14004c73dfe588b903b6c03166582eeaf30529b14072a7b3079e3a684601b9b3024054201f7440b0ee9eb1a7120ff43f713735494aa27b1f8bab60d7f398bca14f6abb2adbf29b04099121438a7974b078a11635b594e9170f1086140b4173822dd697894483e1c6b4e8b8dcd5cb12ca4903bc61e108871d4d915a9093c18ac9b02b6716ce1013ca2c1174e319c1a570215bc9ab5f7564765f7be20524dc3fdf8aa356fd94d445e05ab165ad8bb4a0db096c097618c81098f91443c719416d39837af6de85015dca0de89462b1d8386758b2cf8a99e00953b308032ae44c35e05eb71842922eb69797f68813b59caf266cb6c213569ae3280505421a7e3a0a37fdf8e2ea354fc5422816655394a9454bac542a9298f176e211020d63dee6852c40de02267e2fc9d5e1ff2ad9309506f02a1a71a0501b16d0d36f70cdfd8de78116c0c506ee0b8ddfdeb561acadf31746b5a9dd32c21930884397fb1682164cb565cc14e089d66635a32618f7eb05fe05082b8a3fae620571660a6b89886eac53dec109d7cbb6930ca698a168f301a950be152da1be2b9e07516995e20baceebecb5579d7cdbc16d09f3a50cb3c7dffe33f26686d4ff3f8946ee6475e98cf7b3cf9062b6966e838f865ff3de5fb064a37a21da7bb8dfd2501a29e184f207caaba364f36f2329a77515dcb710e29ffbf73e2bbd773fab1f9a6b005567affff605c132e4e4dd69f36bd201005458cfbd2c658701eb2a700251cefd886b1e674ae816d3f719bac64be649c172ba27a4fd55947d95d53ba4cbc73de97b8af5ed4840b659370c556e7376457f51e5ebb66018849923db82c1c9a819f173cccdb8f3324b239609a300018d0fb094adf5bd7cbb3834c69e6d0b3798065c525b20f040e965e1a161af78ff7561cd874f5f1b75aa0bc77f720589e1b810f831eac5073e6dd46d00a2793f70f7427f0f798f2f53a67e615e65d356e66fe40609a958a05edb4c175bcc383ea0530e67ddbe479a898943c6e3074c6fcc252d6014de3a3d292b03f0d88d312fe221be7be7e3c59d07fa0f2f4029e364f1f355c5d01fa53770d0cd76d82bf7e60f6903bc1beb772e6fde4a70be51d9c7e03c8d6d8dfb361a234ba47c470fe630820bbd920715621b9fbedb49fcee165ead0875e6c2b1af16f50b5d6140cc981122fcbcf7c5a4e3772b3661b628e08380abc545957e59f634705b1bbde2f0b4e055a5ec5676d859be77e20962b645e051a880fddb0180b4555789e1f9344a436a84dc5579e2553f1e5fb0a599c137be36cabbed0319831fea3fddf94ddc7971e4bcf02cdc93294a9aab3e3b13e3b058235b4f4ec06ba4ceaa49d675b4ba80716f3bc6976b1fbf9c8bf1f3e3a4dc1cd83ef9cf816667fb94f1e923ff63fef072e6a19321e4812f96cb0ffa864da50ad74deb76917a336f31dce03ed5f0303aad5e6a83634f9fcc371096f8288b8f02ddded5ff1bb9d49331e4a84dbe1543164438fde9ad71dab024779dcdde0b6602b5ae0a6265c14b94edd83b37403f4b78fcd2ed555b596402c28ee81d87a909c4e8722b30c71ecdd861b05f61f8b1231795c76adba2fdefa451b283a5d527955b9f3de1b9828e7b2e74123dd47062ddcc09b05e7fa13cb2212a6fdbc65d7e852cec463ec6fd929f5b8483cf3052113b13dac91b69f49d1b7d1aec01c4a68e41ce1570101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff071f0104455a6361736830623963346565663862376363343137656535303031653335303039383462366665613335363833613763616331343161303433633432303634383335643334ffffffff010000000000000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000";
let origin = origin.from_hex::<Vec<u8>>().unwrap();
let genesis: chain::Block = serialization::deserialize_with_flags(&origin as &[u8], serialization::DESERIALIZE_ZCASH).unwrap();
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 +153,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]
......
......@@ -23,4 +23,6 @@ pub struct Config {
pub preferable_services: Services,
/// Internet protocol.
pub internet_protocol: InternetProtocol,
/// Serialization flags.
pub serialization_flags: u32,
}
......@@ -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,7 +104,7 @@ 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))
HandshakeState::ReceiveVersion(read_message(stream, self.flags, self.magic, 0))
},
HandshakeState::ReceiveVersion(ref mut future) => {
let (stream, version) = try_ready!(future.poll());
......@@ -125,12 +129,11 @@ impl<A> Future for Handshake<A> where A: AsyncRead + AsyncWrite {
},
HandshakeState::SendVerack { ref mut version, ref mut future } => {
let (stream, _) = try_ready!(future.poll());
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 } => {
......@@ -310,7 +313,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 +342,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 +364,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 +385,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 +407,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);
}
}