diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4f7fe4cdb..c3b4f8f4c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -24,6 +24,7 @@ cache: - stable - beta - tags + - schedules .collect_artifacts: &collect_artifacts artifacts: diff --git a/Cargo.lock b/Cargo.lock index 7841de502..bcd862535 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2179,12 +2179,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", "local-encoding 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-rocksdb-sys 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-rocksdb-sys 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "parity-rocksdb-sys" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4056,7 +4056,7 @@ dependencies = [ "checksum parity-crypto 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c1117f6574377d21309bfa1f7d69ff734120685d92b02c3f362b122585758840" "checksum parity-path 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5962540f99d3895d9addf535f37ab1397886bc2c68e59efd040ef458e5f8c3f7" "checksum parity-rocksdb 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cd55d2d6d6000ec99f021cf52c9acc7d2a402e14f95ced4c5de230696fabe00b" -"checksum parity-rocksdb-sys 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ae07d4bfb2759541957c19f471996b807fc09ef3a5bdce14409b57f038de49f" +"checksum parity-rocksdb-sys 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0e59eda423021494a6cf1be74f6989add403f53157409993f794e17b123cab51" "checksum parity-snappy 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2c5f9d149b13134b8b354d93a92830efcbee6fe5b73a2e6e540fe70d4dd8a63" "checksum parity-snappy-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c2086caac40c79289cb70d7e1c64f5888e1c53f5d38399d3e95101493739f423" "checksum parity-tokio-ipc 0.1.5 (git+https://github.com/nikvolf/parity-tokio-ipc?rev=7c9bbe3bc45d8e72a92b0951acc877da228abd50)" = "" diff --git a/ethcore/res/ethereum/foundation.json b/ethcore/res/ethereum/foundation.json index 4b11041a8..f80fe8934 100644 --- a/ethcore/res/ethereum/foundation.json +++ b/ethcore/res/ethereum/foundation.json @@ -177,8 +177,8 @@ "stateRoot": "0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544" }, "hardcodedSync": { - "header": "f9020ba0c7139a7f4b14c2e12dbe34aeb92711b37747bf8698ecdd6f2c3b1f5f3840e288a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479452e44f279f4203dcf680395379e5f9990a69f13ca06e817f8a9b206f93a393da76a3ece2a74b98eaecc4dae0cfa8f409455e88ccb4a0d739197170d2bc6bbb24fac0ce695982090702082fe1541bb7634f018dfe87b3a038503b7299fb1c113a78b4a3a5dfd997ef32e7fbf722fc178dfcb21e1af1f7f5b9010000020000000000000008000000000010000000000000000000000000000200000002000000000008000000000000000000000000000000000000000000000000000000000000000001004008000000000000000000000000000080000000000008000000080000000000008000000000000000000000000000040210004000000010000000400000000001040000000200000000000000440008000000040000000000000000000000000010000000000000000000000000000000800000000000100002000000000000000000002000000000000000000000000000000000000080000000100000000000000000040400000000000000004000000000000000870c90e059b181c6835ee8018379fb9583065150845b833d198a7777772e62772e636f6da0171fc2d066507ea10c8c2d7bedd5ccc3f0dfb4d590a3998a614013326c0b213a88b4fd884826187393", - "totalDifficulty": "6255555800944520547241", + "header": "f90206a0391c42ff4f047145a6b9a14179c3cc404b31d92f30693e28cf2bba41f47f6329a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794b2930b35844a230f00e51431acae96fe543a0347a0fb280d4457e60a0b96577e1dde9e00905102cfd36def5c5b31dcc2284636136ea077f739c324e35c7448b14aa02186973d3c74cc1ab081498cd0c487a604873723a0e462d76b5204d14b13d1f1b39ea048a3b637f91d42c729c367d5bbdbd0a72d70b90100008003410402005000200009400030c40490500208480008414000a40048806408000080802008204400010001800c0020080c0a00400105a9080820400900240000084012030a1504030508000200005c4404a0c3490820000010400811040004708a1006910211444040c28001a800e920d00000940c200119111a10401001008044214002002080c21081801e008a320848a204400042400898004004010028840181106210080254a081112480031000410202440092c880be3894000120050500860880000108000c0080009e0000204007212840808cb80200601024020000210280100c018540b28a1041a62400000108204084000008808040000004870bc009a1914d7f8362f801837a121d8379ee5a845bbd53ca8573696e6731a0abce0f90ce69f740080eeb94d1cb13981fafe3bc6d020a44815acd86cbd3fc0a889501b04c0614e053", + "totalDifficulty": "7128515864594819065361", "CHTs": [ "0x0eb474b7721727204978e92e27d31cddff56471911e424a4c8271c35f9c982cc", "0xe10e94515fb5ffb7ffa9bf50db4a959b3f50c2ff75e0b8bd5f5e038749e52a11", @@ -3216,7 +3216,137 @@ "0xf344c0cf6516f0fa6617e48076726aefbdaaf5a31f67ad8199bc3f6e426bf904", "0x3f3d2d33f36ba9009e9a72f3f5bbcb5df5392a19fc7afc8d37823aaf52b03477", "0x346a89411f090d559ff90e670bf0a385b1b09f117fc9ffa18b09d3b6d5d8e45c", - "0x5bc5689e2b4572b8ceea472cc7827e22cbfd018920beebf5c5b25f65f5cd5357" + "0x5bc5689e2b4572b8ceea472cc7827e22cbfd018920beebf5c5b25f65f5cd5357", + "0xda418efcaa0076f77e4d2f0c57fc32fa67179a5631d9df52d56497113d0e87af", + "0x5a8050832e835202695129f6f384652827e61ea5f1be7ff300183201d8bd6b4d", + "0xd9f444c382da42c310bd2f05955187163ae7b224e5efd44ab95af332e197d374", + "0x9ef2c5bad361117eedbc2adcb72a2ef5eba4caf3a99a0cbb2a65a94d185e48ae", + "0x7e3e089bc46b00a4174d90003379c382ab5bd84d092b9c4db3189d2bdc24f00b", + "0x94f50fb12eed909d251fe69adb1a1f214776cb029d487360b55c3a2abb663d7e", + "0xd3e1f4244dea40d0741255db2dae72103e263390e0ccfdefcbb2da59ecc5ec9f", + "0x6808bf0cb7d4b677527de762b6db8ddf74a1b272349f34f44505912bd95d62f3", + "0xbf7672ac474b5b849bc086ff8455216f015c8fc7660436dee153522ef6991c04", + "0xe79d27a369cdd5455ddbc6bd9158cd1870aa895b3c3971d07f1555b95ed02ac3", + "0xfa9e20a36c11b0dfbf7e9c62872a6423f5460dfd18e447481461a41176678262", + "0xaafb6c407910341bedc82c0f260cdef75ce5653f644b93a465cb990247a32986", + "0x5058e655e0c179e6c20f48fbd08c2f34f9341f6c07972ff40f55bfabbc783b12", + "0x28d2e7c852de8602a764ff693b6881af18ddadd67fc7eff481f48ac20ebf32f6", + "0xf82e09e7916f61b5cfdc3dcf193bf9d535f2b33f93a06c90fbdc78b3aac6b7ef", + "0x626f3cca9e1a9e5e123e34485c8697c758ffc32213a727665065dd6abd2babe5", + "0xb7f1c07f673d903daa61dec649eb12286a7a0568ee36ecfb1023ec41427c8dd0", + "0x8d1d42bfe88dbe4c621cf68d380dc57e7768121a815546bb4aab29b7486da9ee", + "0x79835acd7266bce85978f481aa3c58f3bab9106d72892df8579e472dc95c6899", + "0x0911c9c804bbe9be0aebab6c92f5b71a893f72a9d0cd35a51b0e8cd19ab0c02a", + "0x7fd2eff10936d8d12fd9a1c6d27e77cbec4e48253465eb7e65876134ff60c8ec", + "0xc739ad4255415e2831c6996673f3d02dc79f6e6d6822f7dee23bff5b94833c3a", + "0x2559faafbae0852fe5a1c924f0e4f6ccdf4fd22f483148b3672a3e7b3692b669", + "0xca37f0aa3d375dbddc0b426c9564fe68f10b0a4cbbf1ab87f97b27b44878f2fb", + "0x00ba40205d1bd46ad5b5e73cd5b1f3418bd892586d5a4647ac9a6d158f15bd93", + "0xfa6d25c829299535e6b80af81a2416d10ed6903117e73c656b979a5f5abe3ee0", + "0xfd82d8944315cfb228a8fa416c18ff82cbd8869c3babbd3389dca6dd66797785", + "0xd8834cc29788cb40ec901725419df8c031a13e190756a6352696de870eaf4671", + "0xdf6843a52bf55e0f4404e7bdf144bb17d5c47a72ef9482e712090ac9730a7f52", + "0x4c2c562f835966c72985f7cca89a3b1a7b0d4cb04623dc96e337daa35a2f5925", + "0x49d2afd87e83a04059dbf3ef4e2598b8d0c495ab1cf91ed3004e16a608e910c2", + "0x5be64774739c001c239efae1ce9f2a5706cc6e3054ddf24b03c09358f2f4852f", + "0x678f789dc8c409653b36f4d2015338165d3bc6a73f2a77ebfe438676b8412d7a", + "0xf87c8fbf02d8e84cf72680e6b9a8b8be39fbae9f1eb1047c536d77535494a301", + "0xe2428b952d2c6d60d4925f56b3d8227cd6bc608da2c1b20264befd8b1ad89454", + "0x561a95eb50c663462bb8af3aab336bd745b0571746b10fefa791bc11be777763", + "0x6945f40e3499d2769ceecf499c701015d93fddb607720b18dbbd5a6a2aa46639", + "0x9c35b0367a2b82270d64f11c5299336b21b9f454077dcf7af3b2e434677a31b6", + "0x454dc6bb2443509381e478f1836cb36808e2ecd1a9944072056c292b710072f4", + "0x0c80566f34a46477592560a883a9c01fa393f7a2c9dbb28a54e46a5c017e8596", + "0xeff6a1255090509eccfdea2e591516886c91191f1f02eaae4808ac95009086fc", + "0x37cf60888e5ec75841e7f0533feef7200185a1c9f3253073216d83923c864829", + "0xb169ebb9e418809a96529835bc293782e4fc6310dba450afe3e95a7abdf7cc01", + "0xa3c8d5c71ce0477a247f56bfe95272ea07f0b7f10a8526b6e3ff9a8de8faa9ab", + "0x2bf18db4ee84bafbbabaf05d1d4d383c0d5fc91be6ae902334496996eb3a8e48", + "0x6c116f0d5809a2c28351a737ef3dbd1808685e1fd656e37df6b6e524aa82c918", + "0x21e2c8e019c687fdb360c9bdd4e3a5133488cd2e0365aee3b823120734aa6f27", + "0x20c9a1db9de894ab4f576265da25f391b32c0805c3da76fbfdd0aaf300f88a39", + "0x23ef1f43af87be7396449fc1f89d9766c59e8adf2660812293c65a27482ddb8e", + "0x04a82d3a4a5e7f2507688ecdcdc300d7fb97aa8be92a671d7d42c0b60fa4532b", + "0x99e204c42afd6d4040faad384517d99bd0e077b03310d32223234d2251d6a07c", + "0xe342c0c4295665b9e25773fc9998e18c460e723d0a14efdb59c19b27b9c7011b", + "0xb654b1b8ede0d54a605cda54b4635d2b3c2bb8efd01ebd416e52cc87b590d4f3", + "0x5daabc41eeb6de98336411a03ec0323995e81549941cf32b7e15c765d1b7b39e", + "0x5103fc7f0fc6df43fb081b580bb01476f2b1cbde73e4d0f9d1fa6d8427fae789", + "0xe2ecf5daba51d2f7b22106033fc43f956bd1db0c5ad02bd941bd3d2b96ca21c5", + "0xf152bce5c6d1efb7e22cde72d6b8ca37f556ffb686a13770c5fab46e04837c92", + "0x306007d8091caa5baaa78643307f5abf9a5f03996fc072a9016ba6b487b2017c", + "0xf57308d0c02c6b8e2416c070554c7e29911fa84ef4cf2d934e2322ca262e987c", + "0xb234fe7433d7fd71fe0c6dfc834e4bcbf84a261b95760a6c4eb67d222b9ff392", + "0x753059f3405f60da3aa7cd1aa0cbcfa4d5ef4f2a6ed34b853b2c5ab2181fd383", + "0x096c6630e821816d9f4bd83fbe0ccfd223282f34aae5a49f969ba30b98c324c3", + "0xd3eec9dedb057fbc839c474fc99cb54d89f3f47d896e06e758c98f1cd194b61f", + "0x0d44cb2a83b9a3fa18daac280cf08b46cc637d705488fd9400cd7300475d0a1c", + "0x2e37a3036db99c4cb1c135f5ca6b527fa13b2e80ee421805b7be5d8b16983602", + "0x381e0ca505308b7d3a083e60b0f9cb44c89f84942430ec9e4c5571796ab6a8eb", + "0x90b04d35906c6f5a59c266c3bce7c2b63cea1486f714e272592ef9ecab25b0ee", + "0x9cbea70e760f2ee97537d058d57f395886a2c3a6e769ccd3433b797b8716517b", + "0x4e2167846e8d6f0f6495b5f1443f59bea143b63f242e40186fc6429434d1136e", + "0xcaa0512739d000bb9783fceb46d0427098886e2b7f2e1140855f1a91f843d5b3", + "0xc14df4e379e84591f618e60b5953aa6764146c7822aa1f0e3c2287e20753985a", + "0xf4443154c04fd378b2c3812fee84b774b37d6e12778674403fb5c995379df866", + "0x1a501c2733cc138fb6ff3716899e08dbcd4d75edc18af8972e8a749e45eaf67a", + "0xfc8cb80bb0d0fb490f29aae3067641eef72e9225c558e7e299e0796a2086969d", + "0x2b7895550febf03070485c02d521e7ddd80b94b7fe33a60b7d7ea3545b13e7dd", + "0xfc4137c3cccd45050b5770a40b2f38c43c62b70b07d17bb6d762b405f3d753dc", + "0x86ed22bbbb9fc6600112b91601af4fff56d0ecbe9b3099f91d4477cab8e300f5", + "0x2273a60405ffb04bd024d880c79010f18d58e3c8ca0dc82795a0125364679fa6", + "0x00dfbfe7be3bb2116d9a603a01ac428c0088a2c1477810cd5d3be0d1bd86beab", + "0x7acfb03315585c79e2a47dbe847d24cab0785791f6af7f179fea4f9d6ecb0e0f", + "0xbf6a2e20ee1da5eec12b792bbaec2531e20766ba54bac423011c1057215851db", + "0xb5e94d1e3ba7363d1d79fb62dedd0b6c26b0485052dd64a7093d41ad2d41b890", + "0x9b0cc26f08708814960de8f280ac26d8ed5089a19bcbd2d765059306da22c196", + "0x22d8af121d3e395d3cb4f6ee43c06e6292f1b5ffda672d2e40dba69a2885f5ac", + "0x04bc174272a57189d76aa17de0f76806e8481f4903575ed8c4df12b042637e0e", + "0x06ebd2b6ec4b80280969a92726df5f9cb12d4288b60af617b7040876116656d3", + "0x0e9430513e63b5173271c89b1c91af0b4818d5d14a3034e1228c56c94186a109", + "0x8dc5422ba98d9e58112b052a00d4b82b1db32e22dd7ff2d845619899bd47f277", + "0xde513d40bdbb1e4956b468cece598d77134626a900066b92fb2ecd6fcb5f81c2", + "0x90746299ec75af1eb444ad14ac666ee444aa020fac3fb57796516d8772ec8f45", + "0xaa91c30c62b24f943ee1eec7586b682289541c0355c2726e44424da8686ca24d", + "0x76eb68baae9fb7ed126097f93842dcadfe6e7188d61549d9c0922a9b3ef8e80a", + "0x5aa5b4045e7fe71559a6e93f4a89b135eaef38b9a7f3a84e383ab1ff902ceca9", + "0x504b78f8fc3646e9722e96a5e97d99f2560d4fa3337fa5faf1cc8c8a05f3520d", + "0xffd7a5d7c3b21e8144f7678a9ddc039cf85eb32b09000a600c9f12aa7d6083ed", + "0xcbb4010000e96ff0b50b9627dae032bd50782ccbd51af8af7cfcd6cd184675f7", + "0xb96fabbdd02371bf4a6a0dc00e3874cf43d47246e27163c910c141b6759a4249", + "0x7358419f4e994ff296a37f2e88b238b3de6ba73062073c9467dec52a2df64422", + "0xca90be9f190a1fd0548becfa719a6e4763e92de0e4da4283a33b5f7d2886b425", + "0xa629364f7d6329b008d9c6a0262327bcc12953aa515cdb7b8817e7fe1d746d46", + "0xc5167bd8cac1ea6d14f305c9d4fe075e1875d96353e5236473b6daca5ae9b4fe", + "0xaf4ce2490e9504172a4393cf14e691e947c86a0ec7b53416384a5832b213d6c5", + "0xbfa4853ef2eecc5d99a90e1abfef37ca10c1f823c1d0ad59a1bb19339861241f", + "0xbb5a6584cdc7e4d06ec5fc1514233cc42970f6c332c3a9590978dc9908e58c0a", + "0xe69d7a0766db411e504f09a8f39f0583b2869016bbe95f21dba432bbe8b88442", + "0x89cf4caaaf200881779f5fa6da8ae91ff1c962045dd0622b5ca65c830d3a9d4f", + "0x82d66c631f4c4167e5301d896dbdfe24d8245b1de041fc85eaeb6e35117ed9a0", + "0x957907bc93879681d8682a188622f9bf2c7d2595dbe3e2e34bb01711cc4124d1", + "0xccb3a3380550586696abd3ac267e85c7516b2b682b3c48f66aca94d57500f3b3", + "0xaf56d4650406e70748dc860a7879d8d522599081f8e7011056c976b860703e43", + "0x5d96ac1d2dff8a054d880a44f5d45a1bd18aba29085fcd633b0608351ff1876c", + "0xe051736dad8b9f93a8f1c13031c2b63249925e152685a2e7ec188ee089861b20", + "0x0db8987339e1fae41af5f08e6fa15da5fd80de3431b54e82cf8edbdc792f870e", + "0xcc99097678110af2be8dc07da8d642dce928b7d9e2728fe6fef1fe2eaa81a72a", + "0x2428c1f94ca57c7913b011a68281eee9ee4855e4ed2c97e34a370e649b21acb1", + "0x501ee9580c89b1f67c5b3b69ae5fd1f83852a2f9330f53565bcd04d8a7c0b776", + "0x16ae47cfa19e8046f93a579fa2557b17aeca7892fc7a82b6d539930c8b7c95c9", + "0xda62590043ca70c1cdfc7969cdfa853bddbcef0ef62aabb9f372805322511014", + "0x481b4aeaaa60504c94dcfea966840b381db85183c34cd25b4857300b5c189003", + "0x035dcc47f8670a9f648bcb0232e42fd4876243a7a3bf737b88d723ba187929a7", + "0xebe9bf09e3577865aeb341a06f67bb6e607f10b04ed9f9d733492a9d0e9ceb1a", + "0xad5d85b58af6aef7f81bd6b2407c6e4884ec82b2ae2aeaa24e379a3d35902375", + "0x0f0dd63d7c6c284659283825624140b31a3adaf7cdbb2255faca443e52ebfe84", + "0x40079be1c9394e95b4823895ed380d79333ca2085aed2abd0d766f84d21b7b42", + "0x7cc40ed01b436ce225a3f9c5c2bc7f6f81aee40bb83a54bca2fe899b15f3e2b6", + "0x1b6356e1a83ca5b0eefda1fd62fa959b118d2a19a6a90f182a53414b3fc7f9f0", + "0xae4a71712cc96a5b30b45e3b92c339c2e975e4ed683f4d1fcadcdc121ff7c6bf", + "0x226f6d8c71ec32c5eaab6b01c0fc1d00ae95e60b383d09560e90549b79eb1447", + "0xf3dec779841c9384df93bcefbba8700a292b570b29d286a7c9c5a442b4788a20", + "0x63ef48e80efa45383857adcb0f31076393260cbad058d1938345ad13faae50b4" ] }, "nodes": [ diff --git a/ethcore/res/ethereum/kovan.json b/ethcore/res/ethereum/kovan.json index 453974eaf..336d32bae 100644 --- a/ethcore/res/ethereum/kovan.json +++ b/ethcore/res/ethereum/kovan.json @@ -62,8 +62,8 @@ "gasLimit": "0x5B8D80" }, "hardcodedSync": { - "header": "f9023ea00861b3771ffb84fce48b8ba3c54a09f81e91ccb38c401261f06d370098889a43a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479400e6d2b931f55a3f1701c7389d592a7778897879a071cc81d58cdd21d1e17f7389e55c530cd9f94cc15bb32af6477320682327dcffa06090021a7c09ae5e75e443410ebdb76de04f1eafb0ab910daae96ee6eec560eaa032510bf257dd03b11f3b4761b94b495a5b5a18cd6eb17c77785e0f46e2ffc882b901000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000400000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000090fffffffffffffffffffffffffffffffd8381e001837a12008306697a845b83bd6096d583010b068650617269747986312e32372e30826c698416e0ef58b841117e2088e2835bf2afcd5d48f42b3bf2a1f33435f21f089ead2a6bae7d01c1486e645b460bb3c726a827ff1eb50e0579f3410563bae090fc256cf1d8d594b82100", - "totalDifficulty": "2845866505151538604560067685603735513869853136", + "header": "f90247a01865856fb6e4118598117560df31734c74cf725c8edae4db941055ac0afeb207a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479400e6d2b931f55a3f1701c7389d592a7778897879a054563efd593e9682943065880710af9187131127148575efc8bb51d80dfed41aa0a568a1653a6c7d559711be0b91a8e75db76c678dbdd286c75b88e4f0c0d31171a0dab32c5cbe9b9244a7af00afa7f6042a4ac923573e8f2f025b107abe1e3da999b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000004000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000090fffffffffffffffffffffffffffffffd8389b001837a120083046540845bbd803c9fde830200048f5061726974792d457468657265756d86312e32382e30826c698416ef600fb841387b51dae8bc8daa6cde190d3f44797690b4da1ce5fcfcd54bdbb2a6ee6d8c1f7649081ca28b5cd70067ee9f61e27d8184db83705102d5e1a269f2b631b4d5db01", + "totalDifficulty": "3020091077015059097853315484608800838133866777", "CHTs": [ "0xdb9557458495268ddd69409fc1f66631ed5ff9bf6c479be6eabe5d83a460acac", "0xd413800c22172be6e0b7a36348c90098955991f119ddad32c5b928e8db4deb02", @@ -4220,7 +4220,257 @@ "0x3ef50c81169af169c100f58f3afcb8e2f926d957b2adbaca8787be5d4e8d7233", "0x8783eaeb56ca2d7fec84e0e272b77271fdfd6c14452a2e1dd83de770c5d99a1a", "0x861024460895378ba100c5d0c05e62bb6cac8b21ae529ab5cab39eb6c6cabd90", - "0x1c741ed9eda60e5ac585e2f48f06fb988367c2c40a0d8111bb04b260fe44ec6b" + "0x1c741ed9eda60e5ac585e2f48f06fb988367c2c40a0d8111bb04b260fe44ec6b", + "0x6051d77e0596a911bce132c4bc12be2ae5cf29d113dd52a41b3bc166861149ce", + "0x92c049df5ddb238644015d4e039e169614ed1d926de070952f2407912906cb4b", + "0xa897567fc1ee9437f2876deb3de2b11b8fc00aa07340564031573f0351ec556d", + "0x3e54a8e15218db168960d28369003cdb1a76f8db19384e9e2696ae66a6693d6e", + "0xc5db7ade97cf28f8b61f2c63a0773201ba64f37dadc19c03943b6772aa7a1a50", + "0xda784d1bf64b7efd06558b90cd2436f3e61dc0f7a8370ff92516ed062f461091", + "0xa1d10b0a36ec5169d2df740878d051bf4d38ebc5dc04ae5558daaabc2bfa1471", + "0xcc89a8be2ff74a7bb9e967cfea3cac067aa84cc455a2fdd5449577b52a2b4ff3", + "0xbd23a3e6d3198d81d798c2851c36b954fa6f359bc8fc6e04a0b757e3d0ba053a", + "0x74640f825b9d9f95be69763845aaa0269d3a6ed5aaec88bfd9b5c4139ba7ef41", + "0xc01a29e41af3cc0d0a13ea83f131f3e4828ec3e83dd2fdf9739c139938dfc2b3", + "0x832509e705972acc7efe91475e8d76ac00a12750e194847093825e6c4db9e83b", + "0x63139d1224766ada1318613b9ec5894308efa2473e809d9e37c8305c6965f2cc", + "0x76547e54dc59473093c3fcca1166307cc7d0f4f0e8a35d850507bec216b76476", + "0x3a6a14785272391982cfa690762f5b2aeccc1dc0bb13eab6b9fcfd056f40703a", + "0x603e32b52795c04416d800b6a936343aaaa09898fa97cadc2b157eeaaf3bd6f7", + "0xf241102a3d3f3a9fdc5a1a586b16fdce4280c6c6da04290541eb3cb9c28c7325", + "0x6db6de041bcc7c00104a21bbd487a1e1ddd5e4953f7a503aa992d68a8a7bbc43", + "0x8377d795c55eac07c0acca674e775ed7d8eea35867990c8a776f40965c9ddc68", + "0x48d62d562279641043e405f4d7fbd76050d773103871c5de2c8acc25992db502", + "0xa9ef42d314e15c419537e022753ab46d41318f1fa8784e4363494f395eb6d236", + "0x99572f567eb602a1d9839bd23b41562bb3782eccf9a8893e54b002e685ab378c", + "0xd8cf2fa2291efed46c1a36e1b8837be62e86caacc380aa6397792ae8baf8f3a1", + "0xed2e800df1acb7bba5ee6251592c397a604debd7b0bfc28c8b0002dc40faa8bf", + "0x9ccece195d9e67e318f6d2952bca9486d09f4207c6d8be266cc0eebe41290920", + "0xb20580a5c96c25bb59e1bae6ced3ea5cb69d903f64e648bcb38b799141b3cd5b", + "0x1488647e697452306d2744ca6c709007cf75e2e37da3c7c05006211ba0720824", + "0x009c3dfc5494962c77900fb8da67d7bf2a2f4b855c521b9d50c4aafb1e0735bb", + "0x482428835dfff3ee1da335b36ba3aa1969fa35e89150e5b3c1991f28272d14f5", + "0x6a972044f2076e98833b243c9ed18162d96b46823170ef7c20b1a02d8bbd48c5", + "0x676242effe0fae84110c4933beecfe5ff549b439e54ff5a588add229329e5365", + "0x2441bce77589ebf8019fa8ae870a8529479c6eaa0fed7e0fbd3cc7439dbd4a09", + "0x0b20c25d2c6897c1a8dc9ea1364d3c72d33c97b4d70b9176c3f0a1e3b6ce08a7", + "0x685aa4e279118f8326a90c78e9896e40d9baa62144e2425887dcc704106979c3", + "0xabcab60973f6bc9ec3b596452e7434c4dc89c55c8eea925fc0092d1103c6f86b", + "0xcbf44f106f3f2c0050906b5e344ad22f0e0034067d35402d447311d254516dd0", + "0xcaa67796a8ac69283d7b6304181a988992130ad8441d47b4fdaf236686dc1caa", + "0xad06e6db230bd0bfaa0df59d1ae517ced29d5f11b34f76ef9bb6a73407128b59", + "0x93ef56a4951e4e5c19230918b1219c1f07e9356363503c1410e71486ed338f87", + "0xc6fef02b5bdd4909906c40cf5b999fe9e08e4c0d8bfe59d3c9aa99011136f780", + "0xfed633749700ffdeb0921a537a215ae31c25b85e4f80727376e50c247b4c5a38", + "0xc39d8cc15f4331fb7db2c24ee1163bd164e81ad2ebc43271f841fb25d03835c6", + "0xb13962dcb364ee49e2d0a34dd1a555fa8df363041504ef1e987ce78646d64146", + "0x97e0d3047e2151d53cbd1358da627453558362c6a830910b33f241848b20cffc", + "0x587ea98cbd1da50c0af1986f6ee5e676658c06442e893304708db831fec8e804", + "0x0a1d21212d9bd85a1a39e046c897d1dafb496bfd80762beda2fd3eb1cdc72eb9", + "0x46aad83612f04e7a51fd642de742f713601992e58de4daf24148a3e6f3318aa2", + "0xa65a8a9ed4fb28fcab6ee3af5df4647083c2e735fc652568759fe0426e9a294e", + "0xacd7ed5525cad187f053ba98487cc4abf24f76c8c0e97e71a696d553a3a41b7f", + "0xdcbdcfbaee764bb404bfa5261b5037b9c7ce567a3c1aa9f7280071990320da18", + "0xf195aae79a232b2170a98602efaa2efbdebb3c40d2438e63bf0954e4dc779cb0", + "0xfbb2675a62e2e67baf85e56fcd4cdf2bf89ff7905952155d3cfd4e625fb674d9", + "0x5b955473a35f6b0d24fa8be8009734ecee62f6c4bcf0cafc2335f07c51752fb1", + "0x66f37b268338f4ba1e21eef6884aef245bc36935be1f5eb14ee1d23618f00f5b", + "0xaab809ee86773263043201b83bd445d98a634d8a6da4c389b2336f68381dd481", + "0x509fc38118491458e45c7e8ab1d60c687f50d85fc1c0bf104b531a3b352198ea", + "0x20d1e4f38e83b27b77d55281af40e9f96be098fdbb90730170638c88ab7e435a", + "0xb33711864d62709a98f81d9c5f0a301bd5808d0e8ecef1063c97347af754c8c2", + "0xd69fd6c0fea478bb380b948f5b054f91831cf26d304991d40ebdf0b00a97503c", + "0x87157d452bf57e617ac1dd2372438b0777b83f6087d8223008d823652c634882", + "0x9c54b0172ae0223e6b23f7e000cb6887144e615efb02c74596002dc26d43eb5c", + "0x5b0f87baa8e40f0a2bbc1a76afbe0b21b5e8aae1443f0d38c3ac55c5f942db42", + "0xeb68d93e19860fb9fb76847080edc345972e29ab1ffd417ae5727d3cec79c0eb", + "0xd27026033bba2557c79c4babaf669a399fbc72a2a5cc06c707e24eaacee83bce", + "0x420d887bd82cccac29711c52f4d362b6a7d854e694f8d597d208d0a094fbad8e", + "0x02ff085c6c3c47879a91f511ea4c54a214af8160e07dce8e82a6be9e8299e237", + "0x1f0384e0afaf47ba59aff9f224905950768674c48de0fb0312749b16edb0a347", + "0x55cefaac814e132ff335882a366ea6173bc21fa713e93d8ad92260c84cfd2d85", + "0x58a8dd6e036a05a937a7053be916c0e7f719f2a1905186e7586a9d2dafd5a1a4", + "0x8714d03549461e32a467cefdad60a96788c97172db05c18eb9debf6e6a4d39e8", + "0xd141656c1f57c12feed31dbff3817e1d2af4e1b5cf6aa75d1bb29ea2c0a3ae69", + "0x5ec365177e19fca3c1063e65a9342008aff04ba9d03d53837b598b143504b97a", + "0xc620e23ae73d423bf2628a3de70b1a1f915d80173e0c8d1443a44b91400c5a8a", + "0xc72c2356ed53eae5a4a56bc248d9d2f4e9154f1404780b84781f357cbc7ad2d2", + "0xe60bfe30e5a1a9457ccca65810675e129948b474f391ce64d270200be7ea6beb", + "0xf679887baad8f8e497d60b015156f194b94fc30c6cb1f83fbc4575e99b95a8d5", + "0x654463146799fcfa18a74ffe4f2423fa04c8747c16b789dd24da26d0338d381c", + "0xe8b5406278d9e4622d088976af8b5e6b14cc146a9530c862a42fa5566a247355", + "0x8ecb4735132f769663781f96fb531115190e68390c54e33b250db874e90aebaa", + "0xef13bf38c2ba993c9dea5777e5db348339273d0e6dd1f41867d3b258f24ac4d4", + "0xbbbbeedf7276a857c513f4ebce88e3b531c99cf206eacd1c6c29d3cabab45df4", + "0x89cd50cde2de3ef40de7502241b78e664de53dd4a5e2ed85db62c55be0a4d8a4", + "0x0da2cae061e7dff539c7e39b0b9f63af3217f1a51bc597db957b6a3972cf7186", + "0x57aa87a6daab3c65519de7c1c1360ab33b830d46f169d4e0d3c38e7dadef289b", + "0x85fb1241c4110b4f3a6c197450af8ac47bb24d531219f6cefcc079717b208c84", + "0x52194cfba6bd7d5eb8b438054fbaf5fef387cdb8b1a7ebafe44cdcf4da47b1dd", + "0x7d24eb47a1310f7f4244e825847f634fd4a4224f695a3609c5250dc6052de6d4", + "0x38edeacb93b10653624f77dc05063499daa770b74d6b63ebe656be5a3630b7b8", + "0x4e050f7b9d73c1aea3ce60c8eae8e46b55b6d4c1cd1eae22faf982895871dcd1", + "0xf22b284ed4d97b7d3553600388748721a328052daaf92a58ed5403fd4020a496", + "0xc5fcf858d9a9748045fa0ca1271ba5af780a788c51d693815e0490671be3885b", + "0x2342efdb88226e68173ef84060a0d4dc6c8aa9c9431883beef4a5588f3157fae", + "0xe1599bf452eaacb8dcd51ff835a9ef5761dbce83cfc719813d6a10772ca5fdb3", + "0xb754797393b3216778ea6389361ca5951f365ae4e7ed99ed4cd4c9c76ff442d3", + "0x3fb5f9f3754764155296c6ff4c469109512264c603ece7c78c1231942bb8ac35", + "0xbb347d23c7d703cd2801e2763f1a6c375b5cb2a666ba137c4d6442c3f94688dc", + "0xed3806645b55fd7027dfb7f5f796933049ae558d26ca695a01e1b11333f5e453", + "0xeadb7740432ede4f90c0bc490c15fb377b68de0fc1ee3a56e87e21e7771211fe", + "0xa8c0e907e0b544e7fc3116d47e4cdfc8e8688f5cc4a67cdf600f74be6b79775a", + "0xc6f6b94f2fb4c56066e3c722123b8e85f80ce8baa0427b62c5a2ff937702c481", + "0xfff0b94553a7daaee58a7e15daf9845d1a3ad4917d81d4f23dad27d0262b48ec", + "0xb9084676613e1a063c2b491bef1b984acfbd2dce60a8ed970688239524e31962", + "0x196af717eab2cf09b47db13605ca4864cb0c4189d40c9b618d8a7d3f92831d78", + "0x4fac369653dcfe74d86b7422354d68f7580b1ae0ab359a8b8f8be8582590ea7a", + "0x035ff04f84478354706945480266321d31790f5445028f3e964801fd9a16c78c", + "0x63df70a24370a408bffabbe1c7a4c9b9e40be1cb326ab10d63fe54bb9de50d34", + "0x37b5c558d31128595425ca68deddf5ae7539abc6da838837eb1e0457e092d9ea", + "0x41a9ce82ab27afbc84669368c2e75a15e6386b77034ec316795a896ef9de577d", + "0x08bc6cc18842df4130280823f7676f418f4797d3ddfc544e54267e6456cfac68", + "0xeabc09ffceeb35cc4ec18518d4920bea2f43bf746f23b5524fa405bd874e9d34", + "0x40336744dcfe6f312e17eea83f53538f9999864c41bec43576cfcbef68d12e7d", + "0x3e780dc9c8f2b708527f1eebca75d18507e00e226a00e1b1ddd0b715aa8dd561", + "0xfd6a3c50c4a4d6e1a6fe27fa96f6aa2654573cbb9b839ce8e09a75993e2bf8e5", + "0x166c03d381d6ab94666099024adc95de0ecc9818e5ceb49965767682ca0c73fe", + "0x9805810b802a51a3ae18ce44f6b2c68abfccef2119df2430e4693e291059e222", + "0x353ecd1a0922e819ffdcd634385ebbdb674d247c4fe75e2d5437b659c98424a4", + "0xe75fb8682b706ed6596699d6151db4dcb19f6e71a3b6e34aabc3508c919f5c17", + "0x6e9bab64b10a2341f49e81d862ef3322d3117842e3f1aabc8b774c68484a2a31", + "0x82b5e79ee8d72c3613458c975530bcbba359734a4e9f07015686dfc521230329", + "0x86d48d57ccbe1f1986a4043748b1a0d8d76fd56bc74e7c48c6fd742affa0ee11", + "0x46ee65b9c2fa3e69aa1cd6ba5aaafa7f7aef59224098b60e22994996c927c9c4", + "0xb6983761b177e21899799410dc018f1acd3d417fe35943fbe57207f9f799a100", + "0x594057a8386db6e159d43d136c464c5e3980eae75a73900f7a84ba94803fc6c4", + "0x53c78073c4a4c44d17db85be06f38ab47ecbb7f36ffa87b9db707fd2bc87f391", + "0x4a976673044732e3e8a0987fc8f3c36375e3c4fb3722fcde5259af492ec458c7", + "0x1e2fc8db341a4d9e123ae4ff4f4d8096d8afef47c5d2915c665922bd1de3b00c", + "0x565cd8eb410c6e0b4d67b54d37ff42f6189095965896b0f81566ca502bea34e3", + "0x32d030e4ff6b2f5a560cb7525b5e66ab1f34a1e06531f9b81c48b8a257bd5637", + "0x25a91d756023bb9ae538034bd39b6e698d05fb1393d1328c4fc7e5c14209cce1", + "0x8036f74c4cbaff3bd98820ddd84bc093c95e88d357b341154a3189715225d068", + "0x8bc6bc61f7a57a145b8d728f583e027c8630f0c07e003b189f390ffd11d6f150", + "0xfbeb53fa167d067c9b0a2c0710f7f5931484f7dd90b9456c52c578a15f402d9b", + "0x8d355b208a16b8aa3f7bc5d8864dc7d6a1c4917a97c523274b86e82998d60b63", + "0xc94e45da800d7b56456d55a9aa36ddf9df45e9cfeeacb1116b8c51a0cea34ebd", + "0x81761ec04a8d219aedb2f58aee529e876043b0a476e771957bc03fef9f0780de", + "0x29264094c720151f7448cae053a403aa86fc20649bcf383517e214d1677e893e", + "0x9ac97c7eef9b69dcd73ec7144a0cddfbf0973791beed405202fb4c2d932ec59e", + "0x89611f8e2f9e2e1629f83ec14aaec1656876718c05088e5087887c87b8414c39", + "0x67244fcdba97905472631378fa3a228b649880c2efdd57e5a6c95e9b70ad8456", + "0x0d554cfc4df02560c3e76159d1964c69c39f5df9489bba5516f28a32a4be202e", + "0xce9274a36a0f25a13edef679a5b286bf91a9dc5274354bb6f1ce0ac52557e650", + "0x6017e68689d9f6dca78f42b93a224b445c18b70288a6e4c0d6cc295627dbb1b9", + "0x76791c90f887355878d0a4d8c84ec3990a3159933ecc8d868d196b363153bd5f", + "0xacb6a6c9ec937b3d5cedba26ab6d581fc41cf9a58b0867232e2c8c73d9978cc3", + "0x89f17989ef556a0562c2aa5a2a1d71e5132b89d656bead1ef88ad31073b80cd1", + "0x06efcf8dbadaf28ee719a5b9c017a093fde84a7f4b9966fe3052c0b2fe410ea6", + "0xce16909616f1d97e5853818938b4798030259ddd41e3468f35b940ca901d6817", + "0xd3ff9e9ad14a605a94bdf05dd2639b6fbda28ccf7b2b228f064b0de52410df5b", + "0xb3e8ca9ee88d4c3ce347d82e8f22793ba22b7adc350fd694b1b00b0764c584f9", + "0xe690268a4ec089aced00f9654aa95acb7a8d7270d9428205b103c30a08d142eb", + "0xd685e1460799c51f14273361e31b9739e5212fa538fb8dfbb8e81e8b1d329bbe", + "0x664c293680fb7c5a89ff3c31e81ec8d0c30a6274ef44e4e76bdb9bba83f3c0b3", + "0x44027fd23526685d920d37b032f912159e308286eaac018244006690b4191d4e", + "0x7ea934c3d75a9ecb6a2055dcd5feaf2d4c851eaf360a648d5d87ef40fba2fbd0", + "0xfd97fc801315e5be630ccb3dc983c409a58fc1fc307adc1e4a48fc60c89ea40f", + "0x15aa0c3c732a2c6684d521729dfeb93f62e22e155d85d20e5488e2c86b043142", + "0xba235420ac54100da28cd6f30ff64b8594e73c42f45ca8494fb3d3c4d66651a9", + "0x9948e8489cd94bed4b8e90a8bd35e01ffe38e7c077f587c6c1949caa99cc98e0", + "0xcf66ccdfa85655d7d4c94cffd41f499afdfa2bbddcdaac547223e6ac4d1f9cf1", + "0x7e5382881f710530720b420a3f3ac08211565ecc8fead8ec649cea11f9385c3d", + "0x104576fbb1760c16ce85c3e5757832d53bda83d618500ef677a6a192ff14a5fb", + "0x9e4689bb1ee34635e1106e38ca41833d2dbc1cfacb7635ede5761048a8637c7c", + "0xc8c7f7ac271015da443320f4af650fc71ea0914f4c41252a5b7ec76f329d5268", + "0x46a93ae992001a54119c8d27788e3ef8927dee0a9949b22ece0196a90932c1da", + "0xa69467f9944f1a5e3a46718a99d3cb14930cab6d971baa37bb774cc757e55c2b", + "0x33f7272fdbfb91428a1344df5867300e256fc3cc2e439c777c3feae1cb27b781", + "0x0aaa367f4c7f399edc64ac1754f47aa5c28b0fa208238276de6bd9e424021ce3", + "0xf5f363c3bfa4a23bf221951f4b53a77b27613938babe40f0832d05fdfd252233", + "0xec315af99bdfdcb3cab1f1dcaa5b42ef53f4e3fcf4d921578892a5896fa20e9c", + "0xb580a8e51e875446d7096a20801dded1f7e5b5fac9f47e9361dfc9dd80214013", + "0xb877df38d8f4cebdfb89f26868bdb97ef945da187b44e1cbeafc1d4b7059d713", + "0x78613b9d2d6b639a54ecf1d50a56af80560b436fa632ae636cf354d4a6dd4af8", + "0x80a9d0a5e43558f1d24256baa6940c0074fa84d4b8e7e236054943f9ad5fbe2b", + "0x60f79f699ba1a740c9784f2a8f1b652d4e695ad2d230b110472b95914fd35c8d", + "0xae20de288eb7362a36a1ff236faaed6ddaacf58783d098118bc9fe66b8780651", + "0xcd08003531d6094cabdbe4d971a01b41552784c246bd2a2f749ee9947d1394d6", + "0x676720accf739c380f64748390c1acd2f88d454539866f7326a517c9b629b545", + "0x086b71ac681c0ea369c16b22ca49753b2083ec25b46ba659206433eb060d98c3", + "0x78910ab7d67e67da722ad53b669d8c3a312de3cf362c6254c09581088e920acb", + "0x5bc6e98a830c114cb432091679ac5b3efd25c362d6f99585ce3a027dff95e524", + "0x8d0daff5a97327b615d1535fea44fa33610fd645d93035e1e5e2bb49d4dcef24", + "0xbb46662b884bc6676d98ebf3f2a35ff9190339b72d68520fe40100b4eafaa2a2", + "0x9aa8faaf935c95a60ffae0487844860084a963792ae0bb90a831f825339810ac", + "0xfd77b5d6b6b87bfb0ddcad7b0ed3992e5fe897b16db06b118230b2d292e317e9", + "0xc465a3384c694bc50cbe97ce9f3bc364884651a97a491f7f64e65dc319d1c9f0", + "0xc4634431867d7a302be79e83fb50d01df7f3b950aeede21fcb59b883399b06e4", + "0xfd524c29525cb97a89026ff68048ca6e2a9f522791eadd74447a6c278151d7df", + "0xc7df516c295a58cf4cd5614eee3d2f773a412dcd4926eadad7e935ecae6d8907", + "0xfb915abde0108d6e84354e21a513fa564f5201277e060bb916a9153537fba1f7", + "0x1d3c6a780f1b259e096f4a141ab83cb6bd035407421e2468e743daec211e536f", + "0xb2f47534f060c70f61a7c16f920d0e11b957bb3ef912ed9292f35b8ceda2acea", + "0x03e0ebe6e9992f6921362d463b68f91518d91079c001c6bea7b3452879fdc29c", + "0xd9a7de173a1617ad813a554a56d7c7d2f010ac78d7782e524b35b5c676cb72dc", + "0x90d05d99167e53d34a02c5b66ed6920190370656905465f20efe56499aa0ba6b", + "0x17702606dc895aae35aef034fddf8f7235efcc66e5c9d252347063209c2177b0", + "0x3c416492193d81fc03b5c1964989a314e5ee6d689c638c996f6761b4d7acd6be", + "0x3c6c1162ea9b277f831989ea26e14bb23ce4d72bb9c865e354992559266ceb16", + "0x96de93f849613bb2ffc117bf111d4798b9252649f94f21187da324a3fe363833", + "0x91e50fc6e564cb9d6b7aab3a6e93f6b32944d5a781196a9a8b12ac7f6f527565", + "0xdbefa2bb2ee620d75295d0f3103e06b428f955dba1a792421e435051c46f7933", + "0x78f29df98ef7dce9fe7b4414da90fb4df5d99231ab0a3b7a3e70659986580fe4", + "0x56cf56899c2388d55eb1496ccbe62041d14cf655c9dbc53984d86c22ed281acd", + "0x099f52c675171088550a9e93e1ab17f003190fa3388d956724d422e5925c4813", + "0x9913e4ad8405b8a60fa512fb616c544c6cdc415cb1023aad0669d58cc3810161", + "0xbf5d51369b2510bb57f8fc8e9342890e8bb37049079dc79ab97afc0bcbf3cbf2", + "0x3a012d45d250c818b641fb18b71b622f5bdf0b7a541e0d8de54f61e516ee3ce7", + "0x0233833414d2cff3da0326f7baccf1bd522db5fee290ab4fc0a976934a20358e", + "0x38a0978c955f20cdc32e2013a5373efbfc50924e45e9c4c756291a903f4162b4", + "0x4107f33a14052662a0469ddd646ab6659006df131c4b0f6b0e6cfd331b46fea2", + "0x8074fb5054c755c912bc68b1dc22ae40ba13c06912c8af1c12652eb4d84c6503", + "0xf6d151b8f9c26c3a31366d967dd7338e80e8107b9b81da0a98faf16df9cbc91a", + "0xcebb0256d0a8a4b22d2341ec7c48292c3226caf4aeaa2003ee36dde25cff833b", + "0x5fa9ac499a2642b0cb7ca365062c02588f9c555bcdf584f533ee8e8544b9928d", + "0x800c7f04db30247318b8d4c11d575dca66bf615674fbeb9e8c20f387d907c8e2", + "0xb0a43de06c9d48afefd5411d759e3c6293cbea4a7c6d862b119182ea02af81b7", + "0xb6e7ca0075d28959cf87d716fea885e9e3a0062fc7da1b6e06089c808a632b8a", + "0x734c1b19f0b5972b5215f675cf60c68c12cf6d6bda7b5a95ee9a781482e68365", + "0x1995b08fffb20dedbef592ac23a81d87129ceb396e065265dd4a6cb876beaf09", + "0x051082047a6b579684b5444ce5b75bc630277ec06b0087779387b9d7fcd18fec", + "0x4aabfe145c368e6878e2ccbdfbecf2f1db5c9078650696bb3a584c14fe17177f", + "0x42811ab68b304ce30fe896c52b53d861abc3c8b5e4e740fa97b1695db9a6691f", + "0xd90cdb12ad64f86b2aa7afb781c00301f50206b05f1543b111c2b971ed209c94", + "0x385435507c2ef42b5f1760b97497e8a02a4b5ec4926c3cce8569fc0f4be59ce8", + "0x2d7a4908350c9cf022920cc51e0cad9c3c05d1d14a92d72310b52f984c857101", + "0xceea9c58106f4f806a256f64dc04e1c4b53e6cc5eb048f3df7a14f8de3506e96", + "0x7032f864eb3eae8d198c3f8edd9cc2dfe88b9971cd01b33318dcba004f9b044b", + "0x71bfeb4c183b20fba60e225524c809b0864fa14f5c0137accc36649ed0712e5c", + "0xef0ec5a2761c46827110c20e14fc4aecadc2407541ea046de09a58cda3b2e839", + "0x5e6debf328055c9413fc3eeca28583f917b361a5b5bda9af4306929931a4116a", + "0x1aab81df07eab969189333e5b2930fcc1b88a525ec5bc6af6626fdcb202b8f34", + "0xbdbf97e1558711d4872821b9400e03a811c61096bb838d3126b1c2154f8fb776", + "0x7d8aaee482933ffaa97777af3e4bf69ce7d99afb24e546d2e365d445d3d0190d", + "0x9da421621b14164582b2b877090c9a956f3a7c917031bf743a9ce457b6292369", + "0x050d717f0433a72b17a0e9a1340f26aed5bf17f90c08a5b73e675860ac9c24de", + "0x80551d3ff835aaf987b9ec056a73a3890985ef551431daa9d4aca10c81cac7fd", + "0x625a5b5aed2660d32d2fd8c4d1bfc248365a5cddaf9b5695e3f131629739ec60", + "0x7d86bc2dc5914d16b3d0d882a5db0230b4b688cbd8c81098d2efc5080e589646", + "0xfe42cd832cdffe56426031ba7d837c56d86be72b89ca9f5474bd08db80cfe903", + "0x0ca30e1fd3bf3e16a0e295ecbb442757248b2ad47baf88fc37d6c55901e709f6", + "0x2a83ed111b99844e17fb7aa69854525958255ffea04e0bfdc365264e72b349db", + "0x709779de19590b69864f5b9228b3a1c334724e20be006ef5ae38f8c05eb6f37e", + "0xf09c664d0e2e88ad5418d14481fefdc9e9c46158bc5439ffe0bf6d6d5ecb2eda", + "0xf350785dd3617ef73b0a5bf439ce5c49adca0c041b6b5047a664e5e33967ddf7", + "0x8fcf87571154dc4eb0a73c6ee31cc0db5f4e064cf23a255a408b2f2c7cc9c0e9", + "0x75801fc8867ce7c75b3148c6c022d7702143b93d93c1fc2349e3e969d0179cae", + "0xf14c18bf68ae881d3fb07f631340b00557a83860d0ba0efbfe55fe199176aff6", + "0xbe48c727fb6a32242229eaa09146c76522dcf6bed6d1c6fc1bebf86b5e4ccdb4", + "0x8487b971e383272df82cd812a0bf3a2026b85bc3897b4ce9ce48afa00849fe00", + "0x60d18b465172f59c0d71594b5273a90cb41db24a5d4c9fc37020f9d8c467a4a2", + "0xab4e36d9f17c748c87d89c23b667e3f4e3265e77b62dbd9c92659026f8a53d12" ] }, "accounts": { diff --git a/ethcore/res/ethereum/poacore.json b/ethcore/res/ethereum/poacore.json index b80b3a113..115108f27 100644 --- a/ethcore/res/ethereum/poacore.json +++ b/ethcore/res/ethereum/poacore.json @@ -15,9 +15,14 @@ }, "772000": { "safeContract": "0x83451c8bc04d4ee9745ccc58edfab88037bc48cc" + }, + "5329160": { + "safeContract": "0xa105Db0e6671C7B5f4f350ff1Af6460E6C696e71" } } - } + }, + "blockRewardContractAddress": "0x4d0153D434384128D17243409e02fca1B3EE21D6", + "blockRewardContractTransition": 5761140 } } }, diff --git a/ethcore/res/ethereum/ropsten.json b/ethcore/res/ethereum/ropsten.json index 9adb5f4a2..6e8d9a76e 100644 --- a/ethcore/res/ethereum/ropsten.json +++ b/ethcore/res/ethereum/ropsten.json @@ -62,8 +62,8 @@ "gasLimit": "0x1000000" }, "hardcodedSync":{ - "header": "f9020fa0a415a8dcd55fe9c93372da415ff6897036e48cd3c1a5ff8ffe119eea1096ecd6a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d493479443d58f2096e015db88e44346e73d8c59cb1753bda0100f05d66d36782b7c061c724d8d07619cc61053eda41badc8d2cb9292898ebaa00a60317b490365f40f0528e1f559b0f49facb6638c82a9490d368e963647c704a0118b536c3bdabf90273d527dfc26914c7878176fff16cee8fbb150e00ffcdd29b9010000000000000000040000002040000000000000000000000000000000000000000040020000000000010800000000000010000000000200000800000000600400000000080100c000004002080000000045000000008000080000000020000200404010010200010004000000000008020000008000000000000000108010440000800080000400010000080010820008000410800000100000000000000000000240244000000010000000000010010000000000002000000000000000000004000000020000001000002000000000000000013000000100000800008000200000104000000000000080000080200402010000000000000000001020000008008501602a8414833bc8018347b7a983476d40845b838083904d696e656420627920416e74506f6f6ca0f540bc9cfa258b97576bfb9a79518b2c07ed73a98bc6baa61cf7af4b40ad5b6988965658a406315a8a", - "totalDifficulty": "9811143388018700", + "header": "f90217a00f0e017311206b97b47403eba05a16ada760a691a36f844ab8bc9082a4efedc9a067baeee20ae4f4216ab4b0c41198efd376aca23e44b1d6575c5949955547b72a946a9ecfa04e99726ec105517ac7ae1aba550bea6ca0e64d4fe9bee34d98e127f7f94f17535582d5bc6eeb6219f323b046b9a98c72b5a02d33ce5daab0436707c6d958dcf0bcd311ec7a72d7b33c20784178d5d95bc6e9a0a5b9cd4802fafaa9381ec0aa745cdb7ac953675e9df89474e5fe14fee134cf87b90100000008018000100000000000800000010000000050004000800000800014200010000001000000000001009001000000000000000000000000000000006004020600000000200001000108088002260441000020204000000000000000000280000000000200010001000000041008002000000004004c000000001000000000008000000000000800000400000201000000044001145000000000000001000a0200c04000a00010080100000020000000400002040000000000040000000040200001020000401000000800080080000400010000000200000008020020200000101000000000100400000000004400010020000200000000000001000000008453461c8683402001837a1200832c5216845bbd359199d88301080f846765746888676f312e31302e31856c696e7578a0c1da176f6642888b4369e14349ca7dc125ef7d4f5f7abad61bd7f6b95bfd46bf887d1a171a9f55dd67", + "totalDifficulty": "12027449412394243", "CHTs": [ "0x614648fc0a459451850bdfe353a932b5ff824e1b568478394f78b3ed5427e37a", "0x1eae561c582dbb7f4e041998e084e165d0332c915d3a6da367638a8d24f3fafc", @@ -1977,7 +1977,146 @@ "0xb652952de1bf9e1174e5f6a37b069b437792672a37a9e0159c4f36b6e64306b4", "0xb72dd6cb5df1b00dbbd84e097e2da79af2ce60559697ab4c93b0a8b85b2ee406", "0xb96fd4a94ac30c10f757691f7f06f25a4900fe424f4eb7ccf322e2f95249b914", - "0x99fd442599036f161ccef1ae8088c5ef694c1819f5b76d9d2fa8f979935f69f8" + "0x99fd442599036f161ccef1ae8088c5ef694c1819f5b76d9d2fa8f979935f69f8", + "0x3e53574f6ae31a45ef928f9c37bea6c61e6d728a5ade9851567d3167f5ca3314", + "0xd7e3d08c5b71a7ad8338e8b51ec54cb11ad4d643d129a371af07376f8c47c1d4", + "0x1033c8aed4ec46377f75cc9a6b3297e1da0a7d1e74df20bae9fdf6d037afdc28", + "0x924d621544f3301f9e212fbb95872fce9eb4a4172a11693674de733bfc2b0018", + "0x7f61884149ea4def1444a70c022da1c23f31ecc51bb175905b492236a57c7fde", + "0x40c50785bc0665ab4eb3cec95405e17510c571570a5859ead804530dbcbd1387", + "0xf806491cf778f4796c0f73428e6eaf237da8488af99e9b61d72c56fa03e7051c", + "0x7a9670842dcb12c66f11e357a84849cee227ea5a7351e7c6c9370e9ef2560129", + "0x1c974da4e1073157c10deac8b256c8ced77a030e0500b2b8a90b6ca1d32ab4fa", + "0x97ebcc81ba9c1e04865ee4617daa967dec39f65501be21fbbe929db869d57dd8", + "0xa36e4506065d8b9c662697b18ffe50ed2f6ccfe6d07a065bdad048778cc53668", + "0xb9d5566eb0d40bbb03114d333d1d1dc85b0e780ec63229f3b93b2c84af5f9509", + "0xcd16693573724880c3c83834d516be65c35a861b76b43878e28aa7fcbc961361", + "0x4f60ecd7811acc087fc4557fdfaa1a0b522fe30da1cbae5e7740eec3cff04c00", + "0x9e58573b152bf5008e0ea3fc0d64573211916521a62fb08ba0f1b44c5da12e7d", + "0x2c6693cfd7e5bf9a3d8cef9e186b3da25d07af983564ced6238f9191b020f105", + "0x8cc6149caeafef85ec7b2456f33530459c52b30a5365a2a0022b1c308357f7b4", + "0x6f66863bd9909f687523128569cd0894c4cf41e2eddd5cd9c20d30c446b1711b", + "0x402317752053e7b6d7e2d5512d6397112d80ace0873f5f9d32c023a402ec03b3", + "0x2fcd50a79495057908bd34875e3531e6298488f0d06d043fb6fb0b140895d379", + "0x533ba9669dcee2c6e35713c7eca3bca168a326a36b0e39fcde76cbd35ab3d99d", + "0xdc2e86503e8066bc5fac91fe63544e33568a3c744967b9360458101c3d9df096", + "0xf994b38ba312d8bfb00d428b13a088738d93965b525eae81b45b9be344f99fd2", + "0x0721f3f772958d6a58dba638453b8d004e0c76dc8b4cf6d595b712edddcf002f", + "0x3c650c2c7ebbe7879a15882c3157552e8ae1adebea8f0c65a2dda272cc4ed838", + "0x649fe38e87546703245a7adf5925e8c7a07942750e14d39553a56ca3fcbd8c65", + "0xad204bf42d2a444faa864df8e9d023483a6b6daaa8001e00bb5373a45ed064a3", + "0x2c5cdc73d8ddef2e5c0d47358ac180043e7e246e590a7e8ad2b0a3f9b4e9375d", + "0xf38f6c364bbbbe626e849ca9bb9324c54cf0ba8dfc0b2741a3ff87ce7734adbc", + "0x317efc1cea774849d6219d31c8464a15956da4f3810bf15d4353443f79d98e75", + "0xb6796dccdf4d3cab16b5ec9567237cb988ee94131f3262c2a581180b775e76de", + "0x1fde3fdf2303d080d400c43345a424f50f6551a6a06ad50c6e277d49e8034df3", + "0x4d7bc44a3b56f5e69fd3e5e8c0cd8f5f839a775c4ee381b4b1d0a36656cf91cc", + "0x6051b60fdced0c51aa6a1cab2418c8f21c5d174109d514a4c6de758b2056611b", + "0x3c2f7be830078af3c2c6d1557b3da74d1d5bbfd8094f98886a959aa71ce70b15", + "0x8f296b90a0ece0a3dbec19a801072497c5840f9c0491062cd402db00c2b69f2a", + "0x6c14c4697f8291dbdfdbfea5522798e3f8b17204f80d8370e6d379e6ee659e77", + "0x4e98f63afaa50f8a30b0d352eb5fcb5403c635cf54b41545aa8b48465d23fb1d", + "0xad3059433e981ff12cd0d7dbc11a8d92a65cb39c6e936e9c7db5934d45806492", + "0x1cbb21f28ad2d191d6850c97487e5a733306f2f6ba370723fd5ed37cf6c880a0", + "0x82a0010a1b20d383bff0e5d7ba3751bc0d9161a4817554432558c5c2825babb3", + "0x33e54e93443e87c003d582dc51d0b9981ddcaeac4df0993877739651cbf52a58", + "0x1de8bc150f4142cd45b5d0784e5952abd8de7cba9654af959498c0fd0bcac404", + "0x3ee852f48a1a930d671e53c9c8d8c3c38353ee1737c093960c3f841e6c682e94", + "0xa9c6e05ec91e2a2f2f003419063fe033e37e5353c6e233706e29c08693e35eb8", + "0x649f7328064c55c03249d527dadaedcdbb4cb0e939d94c866844192d99469e05", + "0x3a407d00efcd5fe7bb765347b1a3f231b744349269b3aeb44099f4bdd068eb9e", + "0xa1a20af2f7e61082810ce7e7afe6118bc0ad95e9641e6129027f46af28048107", + "0x0d68fc5e58cacb2d16d99a0e9e612d674754ea51cbee2c68a21f4b0aa926688c", + "0x9b3e58144c014343271c9dc90daa8d2f642954b3eda223d64bbb0ac41380e512", + "0xd3de08b676d4f06bbf4322ed4340caab76e6ab7144c97af91c2bc9c749e65b38", + "0x21d626c9c38087aac6262b64f09398be6e4cbf246100d8c2416cab57e9ac1b68", + "0x563a450e35f40279f5946641a823f596ef3ad22a45b8ec280128546aeb0faf14", + "0xadd9c7128e14e670c7d21d6dfa5c09a11dfd237e90709b087e3329d3cd89b5fd", + "0x258cc0f845d8e7438a707f590f55203c6c51302cef4cfbf788b1c7054688da14", + "0x4309676aa14fa8244e0a089c7013b89c9adf57fa952295b8ddb23fc6545c9870", + "0x5db769765dfb41aefc0f40f06f3d005b30ce1f14f04f653e0c5500f651cd61cb", + "0xbef131c9f19572b05d295d7122fd1a09fe4a8afd4e20c5a0f3cd2785b7eb9882", + "0x3f235228ea537332a041ec75cc6cb5663edaa1c2ed1c1700273af73a5d49bf1c", + "0xc081811bb077c6ebe224b560eb6b81f3f813b26789cb06d96110071ffc25fcb4", + "0x912444c19a5e458b79c89969ed5336f2873267baf2fe729b6f218b74d269b797", + "0x5846fc726eb9627e9d070041b92d76191c4b32e315d33ad18121b8acd01634fd", + "0xc899f45494660034d343670856c13a32b230d047434a4d54a772132ddfe3e182", + "0x11a699c18b04e8cdcd96a43b7465f7bd81f8f64d7ebe79dcaf9201cc897f2746", + "0x8e09b134dc8a1735c060175e9688fd001974bf2e3baa5a8e88dc4c87365e0e07", + "0xa086797ebca0a1d446a9289b7eda920b926e1b595c288a9dea31ad225e6de86f", + "0x0cc04369b6036dff78a9856a5173bb2dde380359a8dbe0126e06d6e763a01c36", + "0x4b5efcac86e03d1f67774769b8bcc5d131c181cd4fa297eaa6cea5ec0cdfaa6f", + "0x47272a21a07ad5e14e3f97b237dab7e33344da4db5b2d31bc7cd0cc2d2c9f1db", + "0x9540755fd321d125b73cb6f1884c2f0b2a821d29362194f5029a5e7ba2d3ed44", + "0x229b88922fe52a78090673775f264cd665fe222002d6add2ed29b7ffd98de717", + "0x8fa2d755d5cc0efb01d9fd6f5ae1f7864404ae111d8ba17e23686ea9b6566336", + "0x33a8f2e0775fd19b1302b985bd6c29d4ab5fc63060bcf3df2c3685ab1b19ce67", + "0xf6d6bebb541ef9b84d779c62adb76774bb38a8eba3823e74e0790dc7401bebbc", + "0xa1f421108d49ed23996e55012613fc05e0f86e00f17251b1ff1e0824d35befc7", + "0x2cc572ed83dc6c604bb455ab050c550184a923f4b13815f06d10ef19dffb3c7a", + "0x28220e7d1a9583d68656f03ef4d6fa3e249c71d1b42698f87ba1fc582493e194", + "0xe8aa37b3214abb1bc167fdb6f10119a4019541f31c76b3b3f8c363bb138bd09e", + "0x825189c2c836dda454b457a03ff83d422bf78df1f368434768690fa7f51c57e0", + "0x5dad65d275e69478c81ecaec5b872660205735d9649ac020f65f5ea6ae972dda", + "0x84a1184d8f94fab280e0593479179348f9184d6fe5a2b2ea9697894c42574473", + "0xbef5a05bc7e1fb94465570144499672d95f31fa241b4c510011f6677e2bf72fb", + "0xd08235ebe6d79a8549bcd3d2414cd8afd2a3e2ca22ced226c60aacad1361ff89", + "0xbab5204ad45ec52860023e7474579e7c95397f3c4ac01db7e446e92c19dceef0", + "0x6c81acf2ff161d423a904c457166ff454ef41571d01e73d56bf9ab892790248d", + "0xaf4a603b808e3ddece42e3e123ea02defb9f8ef2546a95c5a617b6ecdb89c306", + "0xeecdbda25b04eb764e322d9a1e5eefad399c9ced8c77b1e4ecfbefcc90bb403d", + "0x9463f4677a2039ca372b61b16d5bcb7c043b26af04aea4d3f0dcdec7bd222070", + "0x27bfd92799b4cf9699d2bfcb158f6727bb986fc0dee780fc1052366ebc4e6364", + "0x63c3faa1a8fc0d531261cd241b1299d4fc13629abb4cd357eeb130505fbddf94", + "0x9a4535b07ff68862f3396b14b88fa07cff7abdd5744775aeeec6868606eb4712", + "0xae59e7c3e0a1df32f6e027da2983d3c55b4ba4d99e85329361561bd7f13ac629", + "0xcc5dc26b9be8fd8432537d967afe12fc668949e4fcf72d97a40f9214975fa57a", + "0x8f11634c83c7a43be8b98335ba617a64c6379f5f92664055c5e1620791134ddb", + "0x14ce2a69d844e6a46aa244c5aca9fb74c127f2151c7c16f4611ca030df365d8b", + "0xb06f220566a5e62570b9e9e49a8b9d5663501ba145b12260fbf9d4a18a4b19e3", + "0x6274f3cf553c45e6ba7ef644d75bf208e08a8c6325e336aefd35dda9cca3c4d2", + "0xd0d685497c2f2b923d0b9f1590a748da8c684a915a470db58c3105c83d8304e7", + "0xf37fab515f96e655f182f0b6e6aa3602f2cd74773329094772151e8c33d1f9a4", + "0xf6efd731481e8553f1d18b5735166499e787009b484b0dfbe4d35e7930f0d837", + "0xc96132b510863e553e08c54e98b5e9c0067f26e421980a6a3bfd4f07480c4396", + "0xdca9d8182c573871b6d6a184cb9819256398080bcb7fd765e6c69cd972a28d8d", + "0xd632ca6f5d45646726ecd2977ffea5c71a867890633f571b359657c0d096f840", + "0xfe3884dbca6bd3b0087466b04e6a5857ad59d7a25021e1d994d059d20005185b", + "0x7f40eb6fb94b05bb43873a98e9d4eb5f7ac90fb8913240bc0909c6be42922b30", + "0x5113a0808666815cfc52b8ed63c649d96f35c365def36ae623f536241b163c3f", + "0x8e6dbacfb5c593d7d7c2650d3d0115c3702cbb55f73011823a202e69ca33cc70", + "0x8f069ac7caa48bce09fe93f4aaef6784d8a6f7a3a09edb82c7512ec18acc3ab9", + "0xa5525e51fd789c59d3b208efffe09abca47cfd6981d36ab44084b86706c69888", + "0xcb4a7e60d5e8b9d22887ef1e8ce339cfcea0ae1fcbfa9adb766ad05d84182de7", + "0x0a14f23f9066ebdb67df31e66f6b8ab1c089025c0ba56ea56d15f73749f47cb7", + "0x0963e3eba12e41d21af7625b8dc487b637b1789a6ac05fb23062e0166942df68", + "0xcb7ec271b2f42cae0027d22b688b19b9288f2b5d9c43bc5b1ea23b35f5542828", + "0x9b97e6f4b2eeee29ecccf9584dc020c8caa3cae51c82f5b58d279eaf0c6ab4e3", + "0xad7f1963ce9993e6172c2ae90c6e1d4d3d3c52e14284fcc1b1e9a56776afb97e", + "0x52ef2ad7bc2921742dcbac9772f13d5c31be938eb1ad6aceb2fa8a163389cefa", + "0x369ead6d900e64ae0b5028df8574e59b67c61dca418c87ce6461eb4c8535fd30", + "0x7e1a18f6199f05f21f9eb5463e9ffd87637d2fd24a23047fe095895c533cb6a5", + "0xe1b8813a95e511aaec9b358d515e624fbc20e551c56328f843ae90b3c895d3a2", + "0xc2ea59f3d1e7bbe115390a4c210142fe9f9dcb1959764450f5b5292ad90e0fcf", + "0x97d235c3f18e6819c08dab4efe66d0f11f0d06f8ffc9686e3f28400e057e6f4a", + "0xea64f817770252b77b08ca2f579b440ec02e833fc88af7c9c96a8e1e07b2cb2c", + "0x185f5fd1f7001b533dc01783c83b7ab0828a4e2f188cc4e26768c515b4c421f6", + "0x0c9de9844e856a1e4340bf54dcaf9dc66b489304765b5c3c6ca20284f5a0dca6", + "0x4dd1d52da1d260d1f0f63bafc4c816b30cea8ec3434e7d4b63a0eff86997254c", + "0x0b3eb94aa246f7c8c871535ae2d3abe5c1b951e76b77510140ef52d5ea2457ee", + "0x27102708eea5d715799642f213049d8ac9abc3b12c76d147ce443dab28af96d8", + "0x81fb3c4e8dc6c658af2901b7aebf7467b9ae045dd0f58fe8d77f8770ac517fb6", + "0xf68dba4eee635d7494bae6fb9f0c44e739b3121d4bc6f6f21b495a716af3cf52", + "0xcf87b723dc473d313bf9ddfa233056036c5658777e831796f1f56647cd040c8d", + "0x49927c2100039ac496d9c16dd12f0a05c9441b8616c69c726fd2e79ae65e130c", + "0x088195c7251f6b9fa2105e77df5620211b8ca783a77f1a98de6752fc442c26c7", + "0x604de480bcb88e908b90451c4142b99b9cbb479167473befca7bea9b4ca427a3", + "0x642fdaf6bc1abbf261a9480fcf9bb48cf03fb80bdd434c6ab63401856c74fa39", + "0xe6b596393fce7a3023a316ac34a1fac18e18779ca5983791866f857f257592e1", + "0x40384a52564fae5df8c3e41827cdf584e38f3f555a54ca749b7b516619071d85", + "0xe52f7c17a4106594563ae7b724e5613e87d8442177f39a36b946b0e335be0e5b", + "0x7726202a7c255a9d7be47af6f3b44c1e379cda61237866554396fb6ec043482c", + "0x665da353f296cde80e3cbcb9c7f93b107d5676e5cd694b0bd33334d74789beb9" ] }, "nodes": [ diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 81fbc4e6f..09f00515e 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -118,7 +118,7 @@ pub struct TestBlockChainClient { } /// Used for generating test client blocks. -#[derive(Clone)] +#[derive(Clone, Copy)] pub enum EachBlockWith { /// Plain block. Nothing, @@ -242,69 +242,68 @@ impl TestBlockChainClient { *self.error_on_logs.write() = val; } - /// Add blocks to test client. - pub fn add_blocks(&self, count: usize, with: EachBlockWith) { - let len = self.numbers.read().len(); - for n in len..(len + count) { - let mut header = BlockHeader::new(); - header.set_difficulty(From::from(n)); - header.set_parent_hash(self.last_hash.read().clone()); - header.set_number(n as BlockNumber); - header.set_gas_limit(U256::from(1_000_000)); - header.set_extra_data(self.extra_data.clone()); - let uncles = match with { - EachBlockWith::Uncle | EachBlockWith::UncleAndTransaction => { - let mut uncles = RlpStream::new_list(1); - let mut uncle_header = BlockHeader::new(); - uncle_header.set_difficulty(From::from(n)); - uncle_header.set_parent_hash(self.last_hash.read().clone()); - uncle_header.set_number(n as BlockNumber); - uncles.append(&uncle_header); - header.set_uncles_hash(keccak(uncles.as_raw())); - uncles - }, - _ => RlpStream::new_list(0) - }; - let txs = match with { - EachBlockWith::Transaction | EachBlockWith::UncleAndTransaction => { - let mut txs = RlpStream::new_list(1); - let keypair = Random.generate().unwrap(); - // Update nonces value - self.nonces.write().insert(keypair.address(), U256::one()); - let tx = Transaction { - action: Action::Create, - value: U256::from(100), - data: "3331600055".from_hex().unwrap(), - gas: U256::from(100_000), - gas_price: U256::from(200_000_000_000u64), - nonce: U256::zero() - }; - let signed_tx = tx.sign(keypair.secret(), None); - txs.append(&signed_tx); - txs.out() - }, - _ => ::rlp::EMPTY_LIST_RLP.to_vec() - }; + /// Add a block to test client. + pub fn add_block(&self, with: EachBlockWith, hook: F) + where F: Fn(BlockHeader) -> BlockHeader + { + let n = self.numbers.read().len(); - let mut rlp = RlpStream::new_list(3); - rlp.append(&header); - rlp.append_raw(&txs, 1); - rlp.append_raw(uncles.as_raw(), 1); - let unverified = Unverified::from_rlp(rlp.out()).unwrap(); - self.import_block(unverified).unwrap(); - } - } + let mut header = BlockHeader::new(); + header.set_difficulty(From::from(n)); + header.set_parent_hash(self.last_hash.read().clone()); + header.set_number(n as BlockNumber); + header.set_gas_limit(U256::from(1_000_000)); + header.set_extra_data(self.extra_data.clone()); + + header = hook(header); + + let uncles = match with { + EachBlockWith::Uncle | EachBlockWith::UncleAndTransaction => { + let mut uncles = RlpStream::new_list(1); + let mut uncle_header = BlockHeader::new(); + uncle_header.set_difficulty(From::from(n)); + uncle_header.set_parent_hash(self.last_hash.read().clone()); + uncle_header.set_number(n as BlockNumber); + uncles.append(&uncle_header); + header.set_uncles_hash(keccak(uncles.as_raw())); + uncles + }, + _ => RlpStream::new_list(0) + }; + let txs = match with { + EachBlockWith::Transaction | EachBlockWith::UncleAndTransaction => { + let mut txs = RlpStream::new_list(1); + let keypair = Random.generate().unwrap(); + // Update nonces value + self.nonces.write().insert(keypair.address(), U256::one()); + let tx = Transaction { + action: Action::Create, + value: U256::from(100), + data: "3331600055".from_hex().unwrap(), + gas: U256::from(100_000), + gas_price: U256::from(200_000_000_000u64), + nonce: U256::zero() + }; + let signed_tx = tx.sign(keypair.secret(), None); + txs.append(&signed_tx); + txs.out() + }, + _ => ::rlp::EMPTY_LIST_RLP.to_vec() + }; - /// Make a bad block by setting invalid extra data. - pub fn corrupt_block(&self, n: BlockNumber) { - let hash = self.block_hash(BlockId::Number(n)).unwrap(); - let mut header: BlockHeader = self.block_header(BlockId::Number(n)).unwrap().decode().expect("decoding failed"); - header.set_extra_data(b"This extra data is way too long to be considered valid".to_vec()); let mut rlp = RlpStream::new_list(3); rlp.append(&header); - rlp.append_raw(&::rlp::NULL_RLP, 1); - rlp.append_raw(&::rlp::NULL_RLP, 1); - self.blocks.write().insert(hash, rlp.out()); + rlp.append_raw(&txs, 1); + rlp.append_raw(uncles.as_raw(), 1); + let unverified = Unverified::from_rlp(rlp.out()).unwrap(); + self.import_block(unverified).unwrap(); + } + + /// Add a sequence of blocks to test client. + pub fn add_blocks(&self, count: usize, with: EachBlockWith) { + for _ in 0..count { + self.add_block(with, |header| header); + } } /// Make a bad block by setting invalid parent hash. diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 2009534f3..0f5a9f4cc 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -44,7 +44,7 @@ use self::epoch::PendingTransition; use account_provider::AccountProvider; use builtin::Builtin; -use vm::{EnvInfo, Schedule, CreateContractAddress}; +use vm::{EnvInfo, Schedule, CreateContractAddress, CallType, ActionValue}; use error::Error; use header::{Header, BlockNumber}; use snapshot::SnapshotComponents; @@ -163,8 +163,10 @@ pub fn default_system_or_code_call<'a>(machine: &'a ::machine::EthereumMachine, None, Some(code), Some(code_hash), + Some(ActionValue::Apparent(U256::zero())), U256::max_value(), Some(data), + Some(CallType::StaticCall), ) }, }; diff --git a/ethcore/src/machine.rs b/ethcore/src/machine.rs index 8162408e9..c74cc6bf4 100644 --- a/ethcore/src/machine.rs +++ b/ethcore/src/machine.rs @@ -135,8 +135,10 @@ impl EthereumMachine { Some(contract_address), code, code_hash, + None, gas, - data + data, + None, ) } @@ -149,8 +151,10 @@ impl EthereumMachine { contract_address: Option
, code: Option>>, code_hash: Option, + value: Option, gas: U256, - data: Option> + data: Option>, + call_type: Option, ) -> Result, Error> { let env_info = { let mut env_info = block.env_info(); @@ -167,11 +171,11 @@ impl EthereumMachine { origin: SYSTEM_ADDRESS, gas, gas_price: 0.into(), - value: ActionValue::Transfer(0.into()), + value: value.unwrap_or(ActionValue::Transfer(0.into())), code, code_hash, data, - call_type: CallType::Call, + call_type: call_type.unwrap_or(CallType::Call), params_type: ParamsType::Separate, }; let schedule = self.schedule(env_info.number); diff --git a/ethcore/sync/src/block_sync.rs b/ethcore/sync/src/block_sync.rs index 55b23cba4..bf3ffd858 100644 --- a/ethcore/sync/src/block_sync.rs +++ b/ethcore/sync/src/block_sync.rs @@ -28,6 +28,7 @@ use ethcore::client::{BlockStatus, BlockId, BlockImportError, BlockImportErrorKi use ethcore::error::{ImportErrorKind, QueueErrorKind, BlockError}; use sync_io::SyncIo; use blocks::{BlockCollection, SyncBody, SyncHeader}; +use chain::BlockSet; const MAX_HEADERS_TO_REQUEST: usize = 128; const MAX_BODIES_TO_REQUEST: usize = 32; @@ -35,6 +36,26 @@ const MAX_RECEPITS_TO_REQUEST: usize = 128; const SUBCHAIN_SIZE: u64 = 256; const MAX_ROUND_PARENTS: usize = 16; const MAX_PARALLEL_SUBCHAIN_DOWNLOAD: usize = 5; +const MAX_USELESS_HEADERS_PER_ROUND: usize = 3; + +// logging macros prepend BlockSet context for log filtering +macro_rules! trace_sync { + ($self:ident, $fmt:expr, $($arg:tt)+) => { + trace!(target: "sync", concat!("{:?}: ", $fmt), $self.block_set, $($arg)+); + }; + ($self:ident, $fmt:expr) => { + trace!(target: "sync", concat!("{:?}: ", $fmt), $self.block_set); + }; +} + +macro_rules! debug_sync { + ($self:ident, $fmt:expr, $($arg:tt)+) => { + debug!(target: "sync", concat!("{:?}: ", $fmt), $self.block_set, $($arg)+); + }; + ($self:ident, $fmt:expr) => { + debug!(target: "sync", concat!("{:?}: ", $fmt), $self.block_set); + }; +} #[derive(Copy, Clone, Eq, PartialEq, Debug)] /// Downloader state @@ -65,6 +86,7 @@ pub enum BlockRequest { } /// Indicates sync action +#[derive(Eq, PartialEq, Debug)] pub enum DownloadAction { /// Do nothing None, @@ -89,15 +111,17 @@ impl From for BlockDownloaderImportError { /// Block downloader strategy. /// Manages state and block data for a block download process. pub struct BlockDownloader { + /// Which set of blocks to download + block_set: BlockSet, /// Downloader state state: State, /// Highest block number seen highest_block: Option, /// Downloaded blocks, holds `H`, `B` and `S` blocks: BlockCollection, - /// Last impoted block number + /// Last imported block number last_imported_block: BlockNumber, - /// Last impoted block hash + /// Last imported block hash last_imported_hash: H256, /// Number of blocks imported this round imported_this_round: Option, @@ -114,13 +138,20 @@ pub struct BlockDownloader { retract_step: u64, /// Whether reorg should be limited. limit_reorg: bool, + /// consecutive useless headers this round + useless_headers_count: usize, } impl BlockDownloader { - /// Create a new instance of syncing strategy. This won't reorganize to before the - /// last kept state. - pub fn new(sync_receipts: bool, start_hash: &H256, start_number: BlockNumber) -> Self { + /// Create a new instance of syncing strategy. + /// For BlockSet::NewBlocks this won't reorganize to before the last kept state. + pub fn new(block_set: BlockSet, start_hash: &H256, start_number: BlockNumber) -> Self { + let (limit_reorg, sync_receipts) = match block_set { + BlockSet::NewBlocks => (true, false), + BlockSet::OldBlocks => (false, true) + }; BlockDownloader { + block_set: block_set, state: State::Idle, highest_block: None, last_imported_block: start_number, @@ -133,32 +164,15 @@ impl BlockDownloader { download_receipts: sync_receipts, target_hash: None, retract_step: 1, - limit_reorg: true, - } - } - - /// Create a new instance of sync with unlimited reorg allowed. - pub fn with_unlimited_reorg(sync_receipts: bool, start_hash: &H256, start_number: BlockNumber) -> Self { - BlockDownloader { - state: State::Idle, - highest_block: None, - last_imported_block: start_number, - last_imported_hash: start_hash.clone(), - last_round_start: start_number, - last_round_start_hash: start_hash.clone(), - blocks: BlockCollection::new(sync_receipts), - imported_this_round: None, - round_parents: VecDeque::new(), - download_receipts: sync_receipts, - target_hash: None, - retract_step: 1, - limit_reorg: false, + limit_reorg: limit_reorg, + useless_headers_count: 0, } } /// Reset sync. Clear all local downloaded data. pub fn reset(&mut self) { self.blocks.clear(); + self.useless_headers_count = 0; self.state = State::Idle; } @@ -220,45 +234,65 @@ impl BlockDownloader { } /// Add new block headers. - pub fn import_headers(&mut self, io: &mut SyncIo, r: &Rlp, expected_hash: Option) -> Result { + pub fn import_headers(&mut self, io: &mut SyncIo, r: &Rlp, expected_hash: H256) -> Result { let item_count = r.item_count().unwrap_or(0); if self.state == State::Idle { - trace!(target: "sync", "Ignored unexpected block headers"); + trace_sync!(self, "Ignored unexpected block headers"); return Ok(DownloadAction::None) } if item_count == 0 && (self.state == State::Blocks) { return Err(BlockDownloaderImportError::Invalid); } + // The request is generated in ::request_blocks. + let (max_count, skip) = if self.state == State::ChainHead { + (SUBCHAIN_SIZE as usize, (MAX_HEADERS_TO_REQUEST - 2) as u64) + } else { + (MAX_HEADERS_TO_REQUEST, 0) + }; + + if item_count > max_count { + debug!(target: "sync", "Headers response is larger than expected"); + return Err(BlockDownloaderImportError::Invalid); + } + let mut headers = Vec::new(); let mut hashes = Vec::new(); - let mut valid_response = item_count == 0; //empty response is valid - let mut any_known = false; + let mut last_header = None; for i in 0..item_count { let info = SyncHeader::from_rlp(r.at(i)?.as_raw().to_vec())?; let number = BlockNumber::from(info.header.number()); let hash = info.header.hash(); - // Check if any of the headers matches the hash we requested - if !valid_response { - if let Some(expected) = expected_hash { - valid_response = expected == hash; + + let valid_response = match last_header { + // First header must match expected hash. + None => expected_hash == hash, + Some((last_number, last_hash)) => { + // Subsequent headers must be spaced by skip interval. + let skip_valid = number == last_number + skip + 1; + // Consecutive headers must be linked by parent hash. + let parent_valid = (number != last_number + 1) || *info.header.parent_hash() == last_hash; + skip_valid && parent_valid } - } - any_known = any_known || self.blocks.contains_head(&hash); - if self.blocks.contains(&hash) { - trace!(target: "sync", "Skipping existing block header {} ({:?})", number, hash); - continue; + }; + + // Disable the peer for this syncing round if it gives invalid chain + if !valid_response { + debug!(target: "sync", "Invalid headers response"); + return Err(BlockDownloaderImportError::Invalid); } - if self.highest_block.as_ref().map_or(true, |n| number > *n) { - self.highest_block = Some(number); + last_header = Some((number, hash)); + if self.blocks.contains(&hash) { + trace_sync!(self, "Skipping existing block header {} ({:?})", number, hash); + continue; } match io.chain().block_status(BlockId::Hash(hash.clone())) { BlockStatus::InChain | BlockStatus::Queued => { match self.state { - State::Blocks => trace!(target: "sync", "Header already in chain {} ({})", number, hash), - _ => trace!(target: "sync", "Header already in chain {} ({}), state = {:?}", number, hash, self.state), + State::Blocks => trace_sync!(self, "Header already in chain {} ({})", number, hash), + _ => trace_sync!(self, "Header already in chain {} ({}), state = {:?}", number, hash, self.state), } headers.push(info); hashes.push(hash); @@ -273,17 +307,16 @@ impl BlockDownloader { } } - // Disable the peer for this syncing round if it gives invalid chain - if !valid_response { - trace!(target: "sync", "Invalid headers response"); - return Err(BlockDownloaderImportError::Invalid); + if let Some((number, _)) = last_header { + if self.highest_block.as_ref().map_or(true, |n| number > *n) { + self.highest_block = Some(number); + } } match self.state { State::ChainHead => { if !headers.is_empty() { - // TODO: validate heads better. E.g. check that there is enough distance between blocks. - trace!(target: "sync", "Received {} subchain heads, proceeding to download", headers.len()); + trace_sync!(self, "Received {} subchain heads, proceeding to download", headers.len()); self.blocks.reset_to(hashes); self.state = State::Blocks; return Ok(DownloadAction::Reset); @@ -292,34 +325,41 @@ impl BlockDownloader { let oldest_reorg = io.chain().pruning_info().earliest_state; let last = self.last_imported_block; if self.limit_reorg && best > last && (last == 0 || last < oldest_reorg) { - trace!(target: "sync", "No common block, disabling peer"); + trace_sync!(self, "No common block, disabling peer"); return Err(BlockDownloaderImportError::Invalid); } } }, State::Blocks => { let count = headers.len(); - // At least one of the heades must advance the subchain. Otherwise they are all useless. - if count == 0 || !any_known { - trace!(target: "sync", "No useful headers"); + // At least one of the headers must advance the subchain. Otherwise they are all useless. + if count == 0 { + self.useless_headers_count += 1; + trace_sync!(self, "No useful headers ({:?} this round), expected hash {:?}", self.useless_headers_count, expected_hash); + // only reset download if we have multiple subchain heads, to avoid unnecessary resets + // when we are at the head of the chain when we may legitimately receive no useful headers + if self.blocks.heads_len() > 1 && self.useless_headers_count >= MAX_USELESS_HEADERS_PER_ROUND { + trace_sync!(self, "Received {:?} useless responses this round. Resetting sync", MAX_USELESS_HEADERS_PER_ROUND); + self.reset(); + } return Err(BlockDownloaderImportError::Useless); } self.blocks.insert_headers(headers); - trace!(target: "sync", "Inserted {} headers", count); + trace_sync!(self, "Inserted {} headers", count); }, - _ => trace!(target: "sync", "Unexpected headers({})", headers.len()), + _ => trace_sync!(self, "Unexpected headers({})", headers.len()), } Ok(DownloadAction::None) } /// Called by peer once it has new block bodies - pub fn import_bodies(&mut self, r: &Rlp) -> Result<(), BlockDownloaderImportError> { + pub fn import_bodies(&mut self, r: &Rlp, expected_hashes: &[H256]) -> Result<(), BlockDownloaderImportError> { let item_count = r.item_count().unwrap_or(0); if item_count == 0 { return Err(BlockDownloaderImportError::Useless); } else if self.state != State::Blocks { - trace!(target: "sync", "Ignored unexpected block bodies"); + trace_sync!(self, "Ignored unexpected block bodies"); } else { let mut bodies = Vec::with_capacity(item_count); for i in 0..item_count { @@ -327,8 +367,13 @@ impl BlockDownloader { bodies.push(body); } - if self.blocks.insert_bodies(bodies) != item_count { - trace!(target: "sync", "Deactivating peer for giving invalid block bodies"); + let hashes = self.blocks.insert_bodies(bodies); + if hashes.len() != item_count { + trace_sync!(self, "Deactivating peer for giving invalid block bodies"); + return Err(BlockDownloaderImportError::Invalid); + } + if !all_expected(hashes.as_slice(), expected_hashes, |&a, &b| a == b) { + trace_sync!(self, "Deactivating peer for giving unexpected block bodies"); return Err(BlockDownloaderImportError::Invalid); } } @@ -336,25 +381,30 @@ impl BlockDownloader { } /// Called by peer once it has new block bodies - pub fn import_receipts(&mut self, _io: &mut SyncIo, r: &Rlp) -> Result<(), BlockDownloaderImportError> { + pub fn import_receipts(&mut self, r: &Rlp, expected_hashes: &[H256]) -> Result<(), BlockDownloaderImportError> { let item_count = r.item_count().unwrap_or(0); if item_count == 0 { return Err(BlockDownloaderImportError::Useless); } else if self.state != State::Blocks { - trace!(target: "sync", "Ignored unexpected block receipts"); + trace_sync!(self, "Ignored unexpected block receipts"); } else { let mut receipts = Vec::with_capacity(item_count); for i in 0..item_count { let receipt = r.at(i).map_err(|e| { - trace!(target: "sync", "Error decoding block receipts RLP: {:?}", e); + trace_sync!(self, "Error decoding block receipts RLP: {:?}", e); BlockDownloaderImportError::Invalid })?; receipts.push(receipt.as_raw().to_vec()); } - if self.blocks.insert_receipts(receipts) != item_count { - trace!(target: "sync", "Deactivating peer for giving invalid block receipts"); + let hashes = self.blocks.insert_receipts(receipts); + if hashes.len() != item_count { + trace_sync!(self, "Deactivating peer for giving invalid block receipts"); + return Err(BlockDownloaderImportError::Invalid); + } + if !all_expected(hashes.as_slice(), expected_hashes, |a, b| a.contains(b)) { + trace_sync!(self, "Deactivating peer for giving unexpected block receipts"); return Err(BlockDownloaderImportError::Invalid); } } @@ -363,7 +413,7 @@ impl BlockDownloader { fn start_sync_round(&mut self, io: &mut SyncIo) { self.state = State::ChainHead; - trace!(target: "sync", "Starting round (last imported count = {:?}, last started = {}, block = {:?}", self.imported_this_round, self.last_round_start, self.last_imported_block); + trace_sync!(self, "Starting round (last imported count = {:?}, last started = {}, block = {:?}", self.imported_this_round, self.last_round_start, self.last_imported_block); // Check if need to retract to find the common block. The problem is that the peers still return headers by hash even // from the non-canonical part of the tree. So we also retract if nothing has been imported last round. let start = self.last_round_start; @@ -375,12 +425,12 @@ impl BlockDownloader { if let Some(&(_, p)) = self.round_parents.iter().find(|&&(h, _)| h == start_hash) { self.last_imported_block = start - 1; self.last_imported_hash = p.clone(); - trace!(target: "sync", "Searching common header from the last round {} ({})", self.last_imported_block, self.last_imported_hash); + trace_sync!(self, "Searching common header from the last round {} ({})", self.last_imported_block, self.last_imported_hash); } else { let best = io.chain().chain_info().best_block_number; let oldest_reorg = io.chain().pruning_info().earliest_state; if self.limit_reorg && best > start && start < oldest_reorg { - debug!(target: "sync", "Could not revert to previous ancient block, last: {} ({})", start, start_hash); + debug_sync!(self, "Could not revert to previous ancient block, last: {} ({})", start, start_hash); self.reset(); } else { let n = start - cmp::min(self.retract_step, start); @@ -389,10 +439,10 @@ impl BlockDownloader { Some(h) => { self.last_imported_block = n; self.last_imported_hash = h; - trace!(target: "sync", "Searching common header in the blockchain {} ({})", start, self.last_imported_hash); + trace_sync!(self, "Searching common header in the blockchain {} ({})", start, self.last_imported_hash); } None => { - debug!(target: "sync", "Could not revert to previous block, last: {} ({})", start, self.last_imported_hash); + debug_sync!(self, "Could not revert to previous block, last: {} ({})", start, self.last_imported_hash); self.reset(); } } @@ -420,7 +470,7 @@ impl BlockDownloader { State::ChainHead => { if num_active_peers < MAX_PARALLEL_SUBCHAIN_DOWNLOAD { // Request subchain headers - trace!(target: "sync", "Starting sync with better chain"); + trace_sync!(self, "Starting sync with better chain"); // Request MAX_HEADERS_TO_REQUEST - 2 headers apart so that // MAX_HEADERS_TO_REQUEST would include headers for neighbouring subchains return Some(BlockRequest::Headers { @@ -463,8 +513,9 @@ impl BlockDownloader { } /// Checks if there are blocks fully downloaded that can be imported into the blockchain and does the import. - pub fn collect_blocks(&mut self, io: &mut SyncIo, allow_out_of_order: bool) -> Result<(), BlockDownloaderImportError> { - let mut bad = false; + /// Returns DownloadAction::Reset if it is imported all the the blocks it can and all downloading peers should be reset + pub fn collect_blocks(&mut self, io: &mut SyncIo, allow_out_of_order: bool) -> DownloadAction { + let mut download_action = DownloadAction::None; let mut imported = HashSet::new(); let blocks = self.blocks.drain(); let count = blocks.len(); @@ -478,8 +529,8 @@ impl BlockDownloader { if self.target_hash.as_ref().map_or(false, |t| t == &h) { self.state = State::Complete; - trace!(target: "sync", "Sync target reached"); - return Ok(()); + trace_sync!(self, "Sync target reached"); + return download_action; } let result = if let Some(receipts) = receipts { @@ -490,15 +541,15 @@ impl BlockDownloader { match result { Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain), _)) => { - trace!(target: "sync", "Block already in chain {:?}", h); + trace_sync!(self, "Block already in chain {:?}", h); self.block_imported(&h, number, &parent); }, Err(BlockImportError(BlockImportErrorKind::Import(ImportErrorKind::AlreadyQueued), _)) => { - trace!(target: "sync", "Block already queued {:?}", h); + trace_sync!(self, "Block already queued {:?}", h); self.block_imported(&h, number, &parent); }, Ok(_) => { - trace!(target: "sync", "Block queued {:?}", h); + trace_sync!(self, "Block queued {:?}", h); imported.insert(h.clone()); self.block_imported(&h, number, &parent); }, @@ -506,37 +557,34 @@ impl BlockDownloader { break; }, Err(BlockImportError(BlockImportErrorKind::Block(BlockError::UnknownParent(_)), _)) => { - trace!(target: "sync", "Unknown new block parent, restarting sync"); + trace_sync!(self, "Unknown new block parent, restarting sync"); break; }, Err(BlockImportError(BlockImportErrorKind::Block(BlockError::TemporarilyInvalid(_)), _)) => { - debug!(target: "sync", "Block temporarily invalid, restarting sync"); + debug_sync!(self, "Block temporarily invalid: {:?}, restarting sync", h); break; }, Err(BlockImportError(BlockImportErrorKind::Queue(QueueErrorKind::Full(limit)), _)) => { - debug!(target: "sync", "Block import queue full ({}), restarting sync", limit); + debug_sync!(self, "Block import queue full ({}), restarting sync", limit); + download_action = DownloadAction::Reset; break; }, Err(e) => { - debug!(target: "sync", "Bad block {:?} : {:?}", h, e); - bad = true; + debug_sync!(self, "Bad block {:?} : {:?}", h, e); + download_action = DownloadAction::Reset; break; } } } - trace!(target: "sync", "Imported {} of {}", imported.len(), count); + trace_sync!(self, "Imported {} of {}", imported.len(), count); self.imported_this_round = Some(self.imported_this_round.unwrap_or(0) + imported.len()); - if bad { - return Err(BlockDownloaderImportError::Invalid); - } - if self.blocks.is_empty() { // complete sync round - trace!(target: "sync", "Sync round complete"); - self.reset(); + trace_sync!(self, "Sync round complete"); + download_action = DownloadAction::Reset; } - Ok(()) + download_action } fn block_imported(&mut self, hash: &H256, number: BlockNumber, parent: &H256) { @@ -549,4 +597,392 @@ impl BlockDownloader { } } -//TODO: module tests +// Determines if the first argument matches an ordered subset of the second, according to some predicate. +fn all_expected(values: &[A], expected_values: &[B], is_expected: F) -> bool + where F: Fn(&A, &B) -> bool +{ + let mut expected_iter = expected_values.iter(); + values.iter().all(|val1| { + while let Some(val2) = expected_iter.next() { + if is_expected(val1, val2) { + return true; + } + } + false + }) +} + +#[cfg(test)] +mod tests { + use super::*; + use ethcore::client::TestBlockChainClient; + use ethcore::header::Header as BlockHeader; + use ethcore::spec::Spec; + use ethkey::{Generator,Random}; + use hash::keccak; + use parking_lot::RwLock; + use rlp::{encode_list,RlpStream}; + use tests::helpers::TestIo; + use tests::snapshot::TestSnapshotService; + use transaction::{Transaction,SignedTransaction}; + use triehash_ethereum::ordered_trie_root; + + fn dummy_header(number: u64, parent_hash: H256) -> BlockHeader { + let mut header = BlockHeader::new(); + header.set_gas_limit(0.into()); + header.set_difficulty((number * 100).into()); + header.set_timestamp(number * 10); + header.set_number(number); + header.set_parent_hash(parent_hash); + header.set_state_root(H256::zero()); + header + } + + fn dummy_signed_tx() -> SignedTransaction { + let keypair = Random.generate().unwrap(); + Transaction::default().sign(keypair.secret(), None) + } + + fn import_headers(headers: &[BlockHeader], downloader: &mut BlockDownloader, io: &mut SyncIo) -> Result { + let mut stream = RlpStream::new(); + stream.append_list(headers); + let bytes = stream.out(); + let rlp = Rlp::new(&bytes); + let expected_hash = headers.first().unwrap().hash(); + downloader.import_headers(io, &rlp, expected_hash) + } + + fn import_headers_ok(headers: &[BlockHeader], downloader: &mut BlockDownloader, io: &mut SyncIo) { + let res = import_headers(headers, downloader, io); + assert!(res.is_ok()); + } + + #[test] + fn import_headers_in_chain_head_state() { + ::env_logger::try_init().ok(); + + let spec = Spec::new_test(); + let genesis_hash = spec.genesis_header().hash(); + + let mut downloader = BlockDownloader::new(BlockSet::NewBlocks, &genesis_hash, 0); + downloader.state = State::ChainHead; + + let mut chain = TestBlockChainClient::new(); + let snapshot_service = TestSnapshotService::new(); + let queue = RwLock::new(VecDeque::new()); + let mut io = TestIo::new(&mut chain, &snapshot_service, &queue, None); + + // Valid headers sequence. + let valid_headers = [ + spec.genesis_header(), + dummy_header(127, H256::random()), + dummy_header(254, H256::random()), + ]; + let rlp_data = encode_list(&valid_headers); + let valid_rlp = Rlp::new(&rlp_data); + + match downloader.import_headers(&mut io, &valid_rlp, genesis_hash) { + Ok(DownloadAction::Reset) => assert_eq!(downloader.state, State::Blocks), + _ => panic!("expected transition to Blocks state"), + }; + + // Headers are rejected because the expected hash does not match. + let invalid_start_block_headers = [ + dummy_header(0, H256::random()), + dummy_header(127, H256::random()), + dummy_header(254, H256::random()), + ]; + let rlp_data = encode_list(&invalid_start_block_headers); + let invalid_start_block_rlp = Rlp::new(&rlp_data); + + match downloader.import_headers(&mut io, &invalid_start_block_rlp, genesis_hash) { + Err(BlockDownloaderImportError::Invalid) => (), + _ => panic!("expected BlockDownloaderImportError"), + }; + + // Headers are rejected because they are not spaced as expected. + let invalid_skip_headers = [ + spec.genesis_header(), + dummy_header(128, H256::random()), + dummy_header(256, H256::random()), + ]; + let rlp_data = encode_list(&invalid_skip_headers); + let invalid_skip_rlp = Rlp::new(&rlp_data); + + match downloader.import_headers(&mut io, &invalid_skip_rlp, genesis_hash) { + Err(BlockDownloaderImportError::Invalid) => (), + _ => panic!("expected BlockDownloaderImportError"), + }; + + // Invalid because the packet size is too large. + let mut too_many_headers = Vec::with_capacity((SUBCHAIN_SIZE + 1) as usize); + too_many_headers.push(spec.genesis_header()); + for i in 1..(SUBCHAIN_SIZE + 1) { + too_many_headers.push(dummy_header((MAX_HEADERS_TO_REQUEST as u64 - 1) * i, H256::random())); + } + let rlp_data = encode_list(&too_many_headers); + + let too_many_rlp = Rlp::new(&rlp_data); + match downloader.import_headers(&mut io, &too_many_rlp, genesis_hash) { + Err(BlockDownloaderImportError::Invalid) => (), + _ => panic!("expected BlockDownloaderImportError"), + }; + } + + #[test] + fn import_headers_in_blocks_state() { + ::env_logger::try_init().ok(); + + let mut chain = TestBlockChainClient::new(); + let snapshot_service = TestSnapshotService::new(); + let queue = RwLock::new(VecDeque::new()); + let mut io = TestIo::new(&mut chain, &snapshot_service, &queue, None); + + let mut headers = Vec::with_capacity(3); + let parent_hash = H256::random(); + headers.push(dummy_header(127, parent_hash)); + let parent_hash = headers[0].hash(); + headers.push(dummy_header(128, parent_hash)); + let parent_hash = headers[1].hash(); + headers.push(dummy_header(129, parent_hash)); + + let mut downloader = BlockDownloader::new(BlockSet::NewBlocks, &H256::random(), 0); + downloader.state = State::Blocks; + downloader.blocks.reset_to(vec![headers[0].hash()]); + + let rlp_data = encode_list(&headers); + let headers_rlp = Rlp::new(&rlp_data); + + match downloader.import_headers(&mut io, &headers_rlp, headers[0].hash()) { + Ok(DownloadAction::None) => (), + _ => panic!("expected successful import"), + }; + + // Invalidate parent_hash link. + headers[2] = dummy_header(129, H256::random()); + let rlp_data = encode_list(&headers); + let headers_rlp = Rlp::new(&rlp_data); + + match downloader.import_headers(&mut io, &headers_rlp, headers[0].hash()) { + Err(BlockDownloaderImportError::Invalid) => (), + _ => panic!("expected BlockDownloaderImportError"), + }; + + // Invalidate header sequence by skipping a header. + headers[2] = dummy_header(130, headers[1].hash()); + let rlp_data = encode_list(&headers); + let headers_rlp = Rlp::new(&rlp_data); + + match downloader.import_headers(&mut io, &headers_rlp, headers[0].hash()) { + Err(BlockDownloaderImportError::Invalid) => (), + _ => panic!("expected BlockDownloaderImportError"), + }; + } + + #[test] + fn import_bodies() { + ::env_logger::try_init().ok(); + + let mut chain = TestBlockChainClient::new(); + let snapshot_service = TestSnapshotService::new(); + let queue = RwLock::new(VecDeque::new()); + let mut io = TestIo::new(&mut chain, &snapshot_service, &queue, None); + + // Import block headers. + let mut headers = Vec::with_capacity(4); + let mut bodies = Vec::with_capacity(4); + let mut parent_hash = H256::zero(); + for i in 0..4 { + // Construct the block body + let mut uncles = if i > 0 { + encode_list(&[dummy_header(i - 1, H256::random())]).into_vec() + } else { + ::rlp::EMPTY_LIST_RLP.to_vec() + }; + + let mut txs = encode_list(&[dummy_signed_tx()]); + let tx_root = ordered_trie_root(Rlp::new(&txs).iter().map(|r| r.as_raw())); + + let mut rlp = RlpStream::new_list(2); + rlp.append_raw(&txs, 1); + rlp.append_raw(&uncles, 1); + bodies.push(rlp.out()); + + // Construct the block header + let mut header = dummy_header(i, parent_hash); + header.set_transactions_root(tx_root); + header.set_uncles_hash(keccak(&uncles)); + parent_hash = header.hash(); + headers.push(header); + } + + let mut downloader = BlockDownloader::new(BlockSet::NewBlocks, &headers[0].hash(), 0); + downloader.state = State::Blocks; + downloader.blocks.reset_to(vec![headers[0].hash()]); + + // Only import the first three block headers. + let rlp_data = encode_list(&headers[0..3]); + let headers_rlp = Rlp::new(&rlp_data); + assert!(downloader.import_headers(&mut io, &headers_rlp, headers[0].hash()).is_ok()); + + // Import first body successfully. + let mut rlp_data = RlpStream::new_list(1); + rlp_data.append_raw(&bodies[0], 1); + let bodies_rlp = Rlp::new(rlp_data.as_raw()); + assert!(downloader.import_bodies(&bodies_rlp, &[headers[0].hash(), headers[1].hash()]).is_ok()); + + // Import second body successfully. + let mut rlp_data = RlpStream::new_list(1); + rlp_data.append_raw(&bodies[1], 1); + let bodies_rlp = Rlp::new(rlp_data.as_raw()); + assert!(downloader.import_bodies(&bodies_rlp, &[headers[0].hash(), headers[1].hash()]).is_ok()); + + // Import unexpected third body. + let mut rlp_data = RlpStream::new_list(1); + rlp_data.append_raw(&bodies[2], 1); + let bodies_rlp = Rlp::new(rlp_data.as_raw()); + match downloader.import_bodies(&bodies_rlp, &[headers[0].hash(), headers[1].hash()]) { + Err(BlockDownloaderImportError::Invalid) => (), + _ => panic!("expected BlockDownloaderImportError"), + }; + } + + #[test] + fn import_receipts() { + ::env_logger::try_init().ok(); + + let mut chain = TestBlockChainClient::new(); + let snapshot_service = TestSnapshotService::new(); + let queue = RwLock::new(VecDeque::new()); + let mut io = TestIo::new(&mut chain, &snapshot_service, &queue, None); + + // Import block headers. + let mut headers = Vec::with_capacity(4); + let mut receipts = Vec::with_capacity(4); + let mut parent_hash = H256::zero(); + for i in 0..4 { + // Construct the receipts. Receipt root for the first two blocks is the same. + // + // The RLP-encoded integers are clearly not receipts, but the BlockDownloader treats + // all receipts as byte blobs, so it does not matter. + let mut receipts_rlp = if i < 2 { + encode_list(&[0u32]) + } else { + encode_list(&[i as u32]) + }; + let receipts_root = ordered_trie_root(Rlp::new(&receipts_rlp).iter().map(|r| r.as_raw())); + receipts.push(receipts_rlp); + + // Construct the block header. + let mut header = dummy_header(i, parent_hash); + header.set_receipts_root(receipts_root); + parent_hash = header.hash(); + headers.push(header); + } + + let mut downloader = BlockDownloader::new(BlockSet::OldBlocks, &headers[0].hash(), 0); + downloader.state = State::Blocks; + downloader.blocks.reset_to(vec![headers[0].hash()]); + + // Only import the first three block headers. + let rlp_data = encode_list(&headers[0..3]); + let headers_rlp = Rlp::new(&rlp_data); + assert!(downloader.import_headers(&mut io, &headers_rlp, headers[0].hash()).is_ok()); + + // Import second and third receipts successfully. + let mut rlp_data = RlpStream::new_list(2); + rlp_data.append_raw(&receipts[1], 1); + rlp_data.append_raw(&receipts[2], 1); + let receipts_rlp = Rlp::new(rlp_data.as_raw()); + assert!(downloader.import_receipts(&receipts_rlp, &[headers[1].hash(), headers[2].hash()]).is_ok()); + + // Import unexpected fourth receipt. + let mut rlp_data = RlpStream::new_list(1); + rlp_data.append_raw(&receipts[3], 1); + let bodies_rlp = Rlp::new(rlp_data.as_raw()); + match downloader.import_bodies(&bodies_rlp, &[headers[1].hash(), headers[2].hash()]) { + Err(BlockDownloaderImportError::Invalid) => (), + _ => panic!("expected BlockDownloaderImportError"), + }; + } + + #[test] + fn reset_after_multiple_sets_of_useless_headers() { + ::env_logger::try_init().ok(); + + let spec = Spec::new_test(); + let genesis_hash = spec.genesis_header().hash(); + + let mut downloader = BlockDownloader::new(BlockSet::NewBlocks, &genesis_hash, 0); + downloader.state = State::ChainHead; + + let mut chain = TestBlockChainClient::new(); + let snapshot_service = TestSnapshotService::new(); + let queue = RwLock::new(VecDeque::new()); + let mut io = TestIo::new(&mut chain, &snapshot_service, &queue, None); + + let heads = [ + spec.genesis_header(), + dummy_header(127, H256::random()), + dummy_header(254, H256::random()), + ]; + + let short_subchain = [dummy_header(1, genesis_hash)]; + + import_headers_ok(&heads, &mut downloader, &mut io); + import_headers_ok(&short_subchain, &mut downloader, &mut io); + + assert_eq!(downloader.state, State::Blocks); + assert!(!downloader.blocks.is_empty()); + + // simulate receiving useless headers + let head = vec![short_subchain.last().unwrap().clone()]; + for _ in 0..MAX_USELESS_HEADERS_PER_ROUND { + let res = import_headers(&head, &mut downloader, &mut io); + assert!(res.is_err()); + } + + assert_eq!(downloader.state, State::Idle); + assert!(downloader.blocks.is_empty()); + } + + #[test] + fn dont_reset_after_multiple_sets_of_useless_headers_for_chain_head() { + ::env_logger::try_init().ok(); + + let spec = Spec::new_test(); + let genesis_hash = spec.genesis_header().hash(); + + let mut downloader = BlockDownloader::new(BlockSet::NewBlocks, &genesis_hash, 0); + downloader.state = State::ChainHead; + + let mut chain = TestBlockChainClient::new(); + let snapshot_service = TestSnapshotService::new(); + let queue = RwLock::new(VecDeque::new()); + let mut io = TestIo::new(&mut chain, &snapshot_service, &queue, None); + + let heads = [ + spec.genesis_header() + ]; + + let short_subchain = [dummy_header(1, genesis_hash)]; + + import_headers_ok(&heads, &mut downloader, &mut io); + import_headers_ok(&short_subchain, &mut downloader, &mut io); + + assert_eq!(downloader.state, State::Blocks); + assert!(!downloader.blocks.is_empty()); + + // simulate receiving useless headers + let head = vec![short_subchain.last().unwrap().clone()]; + for _ in 0..MAX_USELESS_HEADERS_PER_ROUND { + let res = import_headers(&head, &mut downloader, &mut io); + assert!(res.is_err()); + } + + // download shouldn't be reset since this is the chain head for a single subchain. + // this state usually occurs for NewBlocks when it has reached the chain head. + assert_eq!(downloader.state, State::Blocks); + assert!(!downloader.blocks.is_empty()); + } +} diff --git a/ethcore/sync/src/blocks.rs b/ethcore/sync/src/blocks.rs index 3815084f8..c64843e3b 100644 --- a/ethcore/sync/src/blocks.rs +++ b/ethcore/sync/src/blocks.rs @@ -215,32 +215,28 @@ impl BlockCollection { } /// Insert a collection of block bodies for previously downloaded headers. - pub fn insert_bodies(&mut self, bodies: Vec) -> usize { - let mut inserted = 0; - for b in bodies { - if let Err(e) = self.insert_body(b) { - trace!(target: "sync", "Ignored invalid body: {:?}", e); - } else { - inserted += 1; - } - } - inserted + pub fn insert_bodies(&mut self, bodies: Vec) -> Vec { + bodies.into_iter() + .filter_map(|b| { + self.insert_body(b) + .map_err(|e| trace!(target: "sync", "Ignored invalid body: {:?}", e)) + .ok() + }) + .collect() } /// Insert a collection of block receipts for previously downloaded headers. - pub fn insert_receipts(&mut self, receipts: Vec) -> usize { + pub fn insert_receipts(&mut self, receipts: Vec) -> Vec> { if !self.need_receipts { - return 0; + return Vec::new(); } - let mut inserted = 0; - for r in receipts { - if let Err(e) = self.insert_receipt(r) { - trace!(target: "sync", "Ignored invalid receipt: {:?}", e); - } else { - inserted += 1; - } - } - inserted + receipts.into_iter() + .filter_map(|r| { + self.insert_receipt(r) + .map_err(|e| trace!(target: "sync", "Ignored invalid receipt: {:?}", e)) + .ok() + }) + .collect() } /// Returns a set of block hashes that require a body download. The returned set is marked as being downloaded. @@ -401,9 +397,9 @@ impl BlockCollection { self.blocks.contains_key(hash) } - /// Check if collection contains a block header. - pub fn contains_head(&self, hash: &H256) -> bool { - self.heads.contains(hash) + /// Check the number of heads + pub fn heads_len(&self) -> usize { + self.heads.len() } /// Return used heap size. @@ -421,7 +417,7 @@ impl BlockCollection { self.downloading_headers.contains(hash) || self.downloading_bodies.contains(hash) } - fn insert_body(&mut self, body: SyncBody) -> Result<(), network::Error> { + fn insert_body(&mut self, body: SyncBody) -> Result { let header_id = { let tx_root = ordered_trie_root(Rlp::new(&body.transactions_bytes).iter().map(|r| r.as_raw())); let uncles = keccak(&body.uncles_bytes); @@ -438,7 +434,7 @@ impl BlockCollection { Some(ref mut block) => { trace!(target: "sync", "Got body {}", h); block.body = Some(body); - Ok(()) + Ok(h) }, None => { warn!("Got body with no header {}", h); @@ -453,7 +449,7 @@ impl BlockCollection { } } - fn insert_receipt(&mut self, r: Bytes) -> Result<(), network::Error> { + fn insert_receipt(&mut self, r: Bytes) -> Result, network::Error> { let receipt_root = { let receipts = Rlp::new(&r); ordered_trie_root(receipts.iter().map(|r| r.as_raw())) @@ -461,7 +457,8 @@ impl BlockCollection { self.downloading_receipts.remove(&receipt_root); match self.receipt_ids.entry(receipt_root) { hash_map::Entry::Occupied(entry) => { - for h in entry.remove() { + let block_hashes = entry.remove(); + for h in block_hashes.iter() { match self.blocks.get_mut(&h) { Some(ref mut block) => { trace!(target: "sync", "Got receipt {}", h); @@ -473,7 +470,7 @@ impl BlockCollection { } } } - Ok(()) + Ok(block_hashes.to_vec()) }, hash_map::Entry::Vacant(_) => { trace!(target: "sync", "Ignored unknown/stale block receipt {:?}", receipt_root); diff --git a/ethcore/sync/src/chain/handler.rs b/ethcore/sync/src/chain/handler.rs index 15f234fbb..bbb3db328 100644 --- a/ethcore/sync/src/chain/handler.rs +++ b/ethcore/sync/src/chain/handler.rs @@ -28,6 +28,7 @@ use network::PeerId; use rlp::Rlp; use snapshot::ChunkType; use std::cmp; +use std::mem; use std::collections::HashSet; use std::time::Instant; use sync_io::SyncIo; @@ -292,10 +293,19 @@ impl SyncHandler { let block_set = sync.peers.get(&peer_id) .and_then(|p| p.block_set) .unwrap_or(BlockSet::NewBlocks); - if !sync.reset_peer_asking(peer_id, PeerAsking::BlockBodies) { + let allowed = sync.peers.get(&peer_id).map(|p| p.is_allowed()).unwrap_or(false); + + if !sync.reset_peer_asking(peer_id, PeerAsking::BlockBodies) || !allowed { trace!(target: "sync", "{}: Ignored unexpected bodies", peer_id); return Ok(()); } + let expected_blocks = match sync.peers.get_mut(&peer_id) { + Some(peer) => mem::replace(&mut peer.asking_blocks, Vec::new()), + None => { + trace!(target: "sync", "{}: Ignored unexpected bodies (peer not found)", peer_id); + return Ok(()); + } + }; let item_count = r.item_count()?; trace!(target: "sync", "{} -> BlockBodies ({} entries), set = {:?}", peer_id, item_count, block_set); if item_count == 0 { @@ -315,7 +325,7 @@ impl SyncHandler { Some(ref mut blocks) => blocks, } }; - downloader.import_bodies(r)?; + downloader.import_bodies(r, expected_blocks.as_slice())?; } sync.collect_blocks(io, block_set); Ok(()) @@ -368,10 +378,23 @@ impl SyncHandler { let expected_hash = sync.peers.get(&peer_id).and_then(|p| p.asking_hash); let allowed = sync.peers.get(&peer_id).map(|p| p.is_allowed()).unwrap_or(false); let block_set = sync.peers.get(&peer_id).and_then(|p| p.block_set).unwrap_or(BlockSet::NewBlocks); - if !sync.reset_peer_asking(peer_id, PeerAsking::BlockHeaders) || expected_hash.is_none() || !allowed { - trace!(target: "sync", "{}: Ignored unexpected headers, expected_hash = {:?}", peer_id, expected_hash); + + if !sync.reset_peer_asking(peer_id, PeerAsking::BlockHeaders) { + debug!(target: "sync", "{}: Ignored unexpected headers", peer_id); return Ok(()); } + let expected_hash = match expected_hash { + Some(hash) => hash, + None => { + debug!(target: "sync", "{}: Ignored unexpected headers (expected_hash is None)", peer_id); + return Ok(()); + } + }; + if !allowed { + debug!(target: "sync", "{}: Ignored unexpected headers (peer not allowed)", peer_id); + return Ok(()); + } + let item_count = r.item_count()?; trace!(target: "sync", "{} -> BlockHeaders ({} entries), state = {:?}, set = {:?}", peer_id, item_count, sync.state, block_set); if (sync.state == SyncState::Idle || sync.state == SyncState::WaitingPeers) && sync.old_blocks.is_none() { @@ -399,12 +422,8 @@ impl SyncHandler { downloader.import_headers(io, r, expected_hash)? }; - if let DownloadAction::Reset = result { - // mark all outstanding requests as expired - trace!("Resetting downloads for {:?}", block_set); - for (_, ref mut p) in sync.peers.iter_mut().filter(|&(_, ref p)| p.block_set == Some(block_set)) { - p.reset_asking(); - } + if result == DownloadAction::Reset { + sync.reset_downloads(block_set); } sync.collect_blocks(io, block_set); @@ -415,10 +434,18 @@ impl SyncHandler { fn on_peer_block_receipts(sync: &mut ChainSync, io: &mut SyncIo, peer_id: PeerId, r: &Rlp) -> Result<(), DownloaderImportError> { sync.clear_peer_download(peer_id); let block_set = sync.peers.get(&peer_id).and_then(|p| p.block_set).unwrap_or(BlockSet::NewBlocks); - if !sync.reset_peer_asking(peer_id, PeerAsking::BlockReceipts) { + let allowed = sync.peers.get(&peer_id).map(|p| p.is_allowed()).unwrap_or(false); + if !sync.reset_peer_asking(peer_id, PeerAsking::BlockReceipts) || !allowed { trace!(target: "sync", "{}: Ignored unexpected receipts", peer_id); return Ok(()); } + let expected_blocks = match sync.peers.get_mut(&peer_id) { + Some(peer) => mem::replace(&mut peer.asking_blocks, Vec::new()), + None => { + trace!(target: "sync", "{}: Ignored unexpected bodies (peer not found)", peer_id); + return Ok(()); + } + }; let item_count = r.item_count()?; trace!(target: "sync", "{} -> BlockReceipts ({} entries)", peer_id, item_count); if item_count == 0 { @@ -438,7 +465,7 @@ impl SyncHandler { Some(ref mut blocks) => blocks, } }; - downloader.import_receipts(io, r)?; + downloader.import_receipts(r, expected_blocks.as_slice())?; } sync.collect_blocks(io, block_set); Ok(()) diff --git a/ethcore/sync/src/chain/mod.rs b/ethcore/sync/src/chain/mod.rs index 8941437b7..f5a0e30b8 100644 --- a/ethcore/sync/src/chain/mod.rs +++ b/ethcore/sync/src/chain/mod.rs @@ -109,7 +109,7 @@ use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo, Bl use ethcore::snapshot::{RestorationStatus}; use sync_io::SyncIo; use super::{WarpSync, SyncConfig}; -use block_sync::{BlockDownloader, BlockDownloaderImportError as DownloaderImportError}; +use block_sync::{BlockDownloader, DownloadAction}; use rand::Rng; use snapshot::{Snapshot}; use api::{EthProtocolInfo as PeerInfoDigest, WARP_SYNC_PROTOCOL_ID}; @@ -429,7 +429,7 @@ impl ChainSync { peers: HashMap::new(), handshaking_peers: HashMap::new(), active_peers: HashSet::new(), - new_blocks: BlockDownloader::new(false, &chain_info.best_block_hash, chain_info.best_block_number), + new_blocks: BlockDownloader::new(BlockSet::NewBlocks, &chain_info.best_block_hash, chain_info.best_block_number), old_blocks: None, last_sent_block_number: 0, network_id: config.network_id, @@ -638,13 +638,13 @@ impl ChainSync { pub fn update_targets(&mut self, chain: &BlockChainClient) { // Do not assume that the block queue/chain still has our last_imported_block let chain = chain.chain_info(); - self.new_blocks = BlockDownloader::new(false, &chain.best_block_hash, chain.best_block_number); + self.new_blocks = BlockDownloader::new(BlockSet::NewBlocks, &chain.best_block_hash, chain.best_block_number); self.old_blocks = None; if self.download_old_blocks { if let (Some(ancient_block_hash), Some(ancient_block_number)) = (chain.ancient_block_hash, chain.ancient_block_number) { trace!(target: "sync", "Downloading old blocks from {:?} (#{}) till {:?} (#{:?})", ancient_block_hash, ancient_block_number, chain.first_block_hash, chain.first_block_number); - let mut downloader = BlockDownloader::with_unlimited_reorg(true, &ancient_block_hash, ancient_block_number); + let mut downloader = BlockDownloader::new(BlockSet::OldBlocks, &ancient_block_hash, ancient_block_number); if let Some(hash) = chain.first_block_hash { trace!(target: "sync", "Downloader target set to {:?}", hash); downloader.set_target(&hash); @@ -763,12 +763,10 @@ impl ChainSync { } } - // Only ask for old blocks if the peer has a higher difficulty than the last imported old block - let last_imported_old_block_difficulty = self.old_blocks.as_mut().and_then(|d| { - io.chain().block_total_difficulty(BlockId::Number(d.last_imported_block_number())) - }); + // Only ask for old blocks if the peer has an equal or higher difficulty + let equal_or_higher_difficulty = peer_difficulty.map_or(false, |pd| pd >= syncing_difficulty); - if force || last_imported_old_block_difficulty.map_or(true, |ld| peer_difficulty.map_or(true, |pd| pd > ld)) { + if force || equal_or_higher_difficulty { if let Some(request) = self.old_blocks.as_mut().and_then(|d| d.request_blocks(io, num_active_peers)) { SyncRequester::request_blocks(self, io, peer_id, request, BlockSet::OldBlocks); return; @@ -776,9 +774,9 @@ impl ChainSync { } else { trace!( target: "sync", - "peer {:?} is not suitable for requesting old blocks, last_imported_old_block_difficulty={:?}, peer_difficulty={:?}", + "peer {:?} is not suitable for requesting old blocks, syncing_difficulty={:?}, peer_difficulty={:?}", peer_id, - last_imported_old_block_difficulty, + syncing_difficulty, peer_difficulty ); self.deactivate_peer(io, peer_id); @@ -856,18 +854,39 @@ impl ChainSync { fn collect_blocks(&mut self, io: &mut SyncIo, block_set: BlockSet) { match block_set { BlockSet::NewBlocks => { - if self.new_blocks.collect_blocks(io, self.state == SyncState::NewBlocks) == Err(DownloaderImportError::Invalid) { - self.restart(io); + if self.new_blocks.collect_blocks(io, self.state == SyncState::NewBlocks) == DownloadAction::Reset { + self.reset_downloads(block_set); + self.new_blocks.reset(); } }, BlockSet::OldBlocks => { - if self.old_blocks.as_mut().map_or(false, |downloader| { downloader.collect_blocks(io, false) == Err(DownloaderImportError::Invalid) }) { - self.restart(io); - } else if self.old_blocks.as_ref().map_or(false, |downloader| { downloader.is_complete() }) { + let mut is_complete = false; + let mut download_action = DownloadAction::None; + if let Some(downloader) = self.old_blocks.as_mut() { + download_action = downloader.collect_blocks(io, false); + is_complete = downloader.is_complete(); + } + + if download_action == DownloadAction::Reset { + self.reset_downloads(block_set); + if let Some(downloader) = self.old_blocks.as_mut() { + downloader.reset(); + } + } + + if is_complete { trace!(target: "sync", "Background block download is complete"); self.old_blocks = None; } } + }; + } + + /// Mark all outstanding requests as expired + fn reset_downloads(&mut self, block_set: BlockSet) { + trace!(target: "sync", "Resetting downloads for {:?}", block_set); + for (_, ref mut p) in self.peers.iter_mut().filter(|&(_, ref p)| p.block_set == Some(block_set)) { + p.reset_asking(); } } diff --git a/ethcore/sync/src/tests/chain.rs b/ethcore/sync/src/tests/chain.rs index 0b6c8f7c2..06118df66 100644 --- a/ethcore/sync/src/tests/chain.rs +++ b/ethcore/sync/src/tests/chain.rs @@ -225,32 +225,28 @@ fn propagate_blocks() { #[test] fn restart_on_malformed_block() { + ::env_logger::try_init().ok(); let mut net = TestNet::new(2); - net.peer(1).chain.add_blocks(10, EachBlockWith::Uncle); - net.peer(1).chain.corrupt_block(6); + net.peer(1).chain.add_blocks(5, EachBlockWith::Nothing); + net.peer(1).chain.add_block(EachBlockWith::Nothing, |mut header| { + header.set_extra_data(b"This extra data is way too long to be considered valid".to_vec()); + header + }); net.sync_steps(20); - assert_eq!(net.peer(0).chain.chain_info().best_block_number, 5); + // This gets accepted just fine since the TestBlockChainClient performs no validation. + // Probably remove this test? + assert_eq!(net.peer(0).chain.chain_info().best_block_number, 6); } #[test] -fn restart_on_broken_chain() { +fn reject_on_broken_chain() { let mut net = TestNet::new(2); - net.peer(1).chain.add_blocks(10, EachBlockWith::Uncle); + net.peer(1).chain.add_blocks(10, EachBlockWith::Nothing); net.peer(1).chain.corrupt_block_parent(6); net.sync_steps(20); - assert_eq!(net.peer(0).chain.chain_info().best_block_number, 5); -} - -#[test] -fn high_td_attach() { - let mut net = TestNet::new(2); - net.peer(1).chain.add_blocks(10, EachBlockWith::Uncle); - net.peer(1).chain.corrupt_block_parent(6); - net.sync_steps(20); - - assert_eq!(net.peer(0).chain.chain_info().best_block_number, 5); + assert_eq!(net.peer(0).chain.chain_info().best_block_number, 0); } #[test]