Compare commits

...

2 Commits

Author SHA1 Message Date
Wei Tang
62ccdd7ad4 [beta] Backports (#8558)
* Fetching logs by hash in blockchain database (#8463)

* Fetch logs by hash in blockchain database

* Fix tests

* Add unit test for branch block logs fetching

* Add docs that blocks must already be sorted

* Handle branch block cases properly

* typo: empty -> is_empty

* Remove return_empty_if_none by using a closure

* Use BTreeSet to avoid sorting again

* Move is_canon to BlockChain

* typo: pass value by reference

* Use loop and wrap inside blocks to simplify the code

Borrowed from https://github.com/paritytech/parity/pull/8463#discussion_r183453326

* typo: missed a comment

* Pass on storage keys tracing to handle the case when it is not modified (#8491)

* Pass on storage keys even if it is not modified

* typo: account and storage query

`to_pod_diff` builds both `touched_addresses` merge and storage keys merge.

* Fix tests

* Use state query directly because of suicided accounts

* Fix a RefCell borrow issue

* Add tests for unmodified storage trace

* Address grumbles

* typo: remove unwanted empty line

* ensure_cached compiles with the original signature

* Update wasmi and pwasm-utils (#8493)

* Update wasmi to 0.2

New wasmi supports 32bit platforms and no longer requires a special feature to build for such platforms.

* Update pwasm-utils to 0.1.5

* Show imported messages for light client (#8517)

* Enable WebAssembly and Byzantium for Ellaism (#8520)

* Enable WebAssembly and Byzantium for Ellaism

* Fix indentation

* Remove empty lines

* Don't panic in import_block if invalid rlp (#8522)

* Don't panic in import_block if invalid rlp

* Remove redundant type annotation

* Replace RLP header view usage with safe decoding

Using the view will panic with invalid RLP. Here we use Rlp decoding directly which will return a `Result<_, DecoderError>`. While this path currently should not have any invalid RLP - it makes it safer if ever called with invalid RLP from other code paths.

* Node table sorting according to last contact data (#8541)

* network-devp2p: sort nodes in node table using last contact data

* network-devp2p: rename node contact types in node table json output

* network-devp2p: fix node table tests

* network-devp2p: note node failure when failed to establish connection

* network-devp2p: handle UselessPeer error

* network-devp2p: note failure when marking node as useless
2018-05-07 20:17:52 +02:00
Afri Schoedon
aae451de9e
Betalize 1.11 :) (#8475)
* Betalize 1.11 :)

* Update Gitlab scripts

* Use master as gitlab latest

* Fix snap builds (#8483)

* Update hardcodedSync for Ethereum, Kovan, and Ropsten (#8489)
2018-04-26 09:46:06 +02:00
22 changed files with 5570 additions and 165 deletions

View File

@ -188,7 +188,7 @@ docker-build:
before_script:
- docker info
script:
- if [ "$CI_BUILD_REF_NAME" == "beta-release" ]; then DOCKER_TAG="latest"; else DOCKER_TAG=$CI_BUILD_REF_NAME; fi
- if [ "$CI_BUILD_REF_NAME" == "master" ]; then DOCKER_TAG="latest"; else DOCKER_TAG=$CI_BUILD_REF_NAME; fi
- echo "Tag:" $DOCKER_TAG
- docker login -u $Docker_Hub_User_Parity -p $Docker_Hub_Pass_Parity
- scripts/docker-build.sh $DOCKER_TAG

19
Cargo.lock generated
View File

@ -1770,6 +1770,11 @@ dependencies = [
"tiny-keccak 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nan-preserving-float"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "net2"
version = "0.2.31"
@ -2586,7 +2591,7 @@ dependencies = [
[[package]]
name = "pwasm-utils"
version = "0.1.3"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3625,18 +3630,19 @@ dependencies = [
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-wasm 0.27.5 (registry+https://github.com/rust-lang/crates.io-index)",
"pwasm-utils 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"pwasm-utils 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"vm 0.1.0",
"wasmi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"wasmi 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "wasmi"
version = "0.1.3"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"nan-preserving-float 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-wasm 0.27.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -3888,6 +3894,7 @@ dependencies = [
"checksum msdos_time 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aad9dfe950c057b1bfe9c1f2aa51583a8468ef2a5baba2ebbe06d775efeb7729"
"checksum multibase 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b9c35dac080fd6e16a99924c8dfdef0af89d797dd851adab25feaffacf7850d6"
"checksum multihash 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d49add5f49eb08bfc4d01ff286b84a48f53d45314f165c2d6efe477222d24f3"
"checksum nan-preserving-float 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34d4f00fcc2f4c9efa8cc971db0da9e28290e28e97af47585e48691ef10ff31f"
"checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09"
"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
"checksum ntp 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "143149743832c6543b60a8ef2a26cd9122dfecec2b767158e852a7beecf6d7a0"
@ -3928,7 +3935,7 @@ dependencies = [
"checksum proc-macro2 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "388d7ea47318c5ccdeb9ba6312cee7d3f65dd2804be8580a170fce410d50b786"
"checksum protobuf 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40e2484e639dcae0985fc483ad76ce7ad78ee5aa092751d7d538f0b20d76486b"
"checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07"
"checksum pwasm-utils 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "54d440c3b56eee028aa5d4f18cbed8c6e0c9ae23563b93f344beb7e73854ea02"
"checksum pwasm-utils 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d51e9954a77aab7b4b606dc315a49cbed187924f163b6750cdf6d5677dbf0839"
"checksum quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18c45c4854d6d1cf5d531db97c75880feb91c958b0720f4ec1057135fec358b3"
"checksum quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9e25fa23c044c1803f43ca59c98dac608976dd04ce799411edd58ece776d4"
"checksum quasi_macros 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29cec87bc2816766d7e4168302d505dd06b0a825aed41b00633d296e922e02dd"
@ -4033,7 +4040,7 @@ dependencies = [
"checksum vergen 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c3365f36c57e5df714a34be40902b27a992eeddb9996eca52d0584611cf885d"
"checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum wasmi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d19da510b59247935ad5f598357b3cc739912666d75d3d28318026478d95bbdb"
"checksum wasmi 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46df76793c28cd8f590d5667f540a81c1c245440a17b03560e381226e27cf348"
"checksum webpki 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e1622384bcb5458c6a3e3fa572f53ea8fef1cc85e535a2983dea87e9154fac2"
"checksum webpki-roots 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "155d4060e5befdf3a6076bd28c22513473d9900b763c9e4521acc6f78a75415c"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"

View File

@ -30,7 +30,7 @@ use kvdb::KeyValueDB;
use cache::Cache;
use parking_lot::Mutex;
use super::{ChainDataFetcher, Client, Config as ClientConfig};
use super::{ChainDataFetcher, LightChainNotify, Client, Config as ClientConfig};
/// Errors on service initialization.
#[derive(Debug)]
@ -86,6 +86,11 @@ impl<T: ChainDataFetcher> Service<T> {
})
}
/// Set the actor to be notified on certain chain events
pub fn add_notify(&self, notify: Arc<LightChainNotify>) {
self.client.add_listener(Arc::downgrade(&notify));
}
/// Register an I/O handler on the service.
pub fn register_handler(&self, handler: Arc<IoHandler<ClientIoMessage> + Send>) -> Result<(), IoError> {
self.io_service.register_handler(handler)

View File

@ -13,9 +13,9 @@
"eip150Transition": "0x0",
"eip160Transition": "0x0",
"ecip1017EraRounds": 10000000,
"eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff"
"eip161dTransition": "0x7fffffffffffffff",
"eip100bTransition": 2000000
}
}
},
@ -29,7 +29,12 @@
"chainID": "0x40",
"eip155Transition": "0x0",
"eip98Transition": "0x7fffffffffffff",
"eip86Transition": "0x7fffffffffffff"
"eip86Transition": "0x7fffffffffffff",
"wasmActivationTransition": 2000000,
"eip140Transition": 2000000,
"eip211Transition": 2000000,
"eip214Transition": 2000000,
"eip658Transition": 2000000
},
"genesis": {
"seal": {
@ -60,6 +65,10 @@
"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
"0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
"0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
"0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }
"0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
"0000000000000000000000000000000000000005": { "builtin": { "name": "modexp", "activate_at": 2000000, "pricing": { "modexp": { "divisor": 20 } } } },
"0000000000000000000000000000000000000006": { "builtin": { "name": "alt_bn128_add", "activate_at": 2000000, "pricing": { "linear": { "base": 500, "word": 0 } } } },
"0000000000000000000000000000000000000007": { "builtin": { "name": "alt_bn128_mul", "activate_at": 2000000, "pricing": { "linear": { "base": 40000, "word": 0 } } } },
"0000000000000000000000000000000000000008": { "builtin": { "name": "alt_bn128_pairing", "activate_at": 2000000, "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } }
}
}

View File

@ -174,8 +174,8 @@
"stateRoot": "0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544"
},
"hardcodedSync": {
"header": "f90219a061d694007fbaca6e23e73e29c8c6a60099abc740ab7e27ae3cd1b9c6a47efef7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347945a0b54d5dc17e0aadc383d2db43b0a0d3e029c4ca0a2f1bdabc1a72737de1c22a76cacc8fc162366904f759a99db7d6d19efee3090a0ac5f5b236e8977928a2ce43c7569ea5a74919643cb0b06d7540407b1ea1298f0a04356ddc5d77c83923a6541260308be167386e0969a608a017770c9e38091cfcab90100a00010002001009080011010141088000004000080081100000a002023000002204204801204084000c000010008000000000880080020c0000440200460000290005010c01c80800080004800100406003380000400402040000028084002a80087000008090a00200100544020019580022000000306100a0080100084020006809000e80000010000254810002000000a240050014200002002c10809202030006422022000203012000241089300080400000009001021020200012410348500028290230408100302000000058c0000020c08c20480081040020260004008481000080000800010010060020000e00020002140100a8988000004400201870b9af4a66df8038350a8018379d54483799eba845ab0426d984554482e45544846414e532e4f52472d3231323134313232a05eeccc80302d8fecca48a47be03654b5a41b5e5f296f271f910ebae631124f518890074810024c6c2b",
"totalDifficulty": "3144406426008470895785",
"header": "f90216a03b798fd7d7c51f61fdbe7a08d6d2257eea4501c12dfc5442146b85837c0da51fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794ea674fdde714fd979de3edf0f56aa9716b898ec8a0a2df7c321f2a532f63cdaf4e234227dd067f3782787db2ac892e875a8cb6842fa0c3a3f2c96c938633c7a99531a3876d544dbb8d5fac06879bea8e3cc5b6ece09da0221863f4a4fa6ca8dc7b6eed0eaefea36a5069f06ba9a61e78b87b634b5e4409b9010000a02080204012000000004100800000c0a08040041160000000740200200148000000000104011040800081808000102001180000000a80000011401020002c14008402000000100014400e20082080400000aa004100000000d10e8a0026180020882008200400a548000000201010088080000c0020800000001004046200600000052004020001800400800400420001800084002c1200040088028840004604020820400000264000005808500400410451c0808020140380c02014000440000002010422080800000240000000048a80072140000400409020020220810010020018008021800280a05008020000400000000044178000008000044410870b075e7ebe9d268353f001837a11f88379cd17845adfefa59565746865726d696e652d6177732d61736961312d32a0c92755fe5da24ea52d89783e387d88e1c2e24ac202641dd9906fc704a88979d28818d4dcc0009d0541",
"totalDifficulty": "3828700463149109414955",
"CHTs": [
"0x0eb474b7721727204978e92e27d31cddff56471911e424a4c8271c35f9c982cc",
"0xe10e94515fb5ffb7ffa9bf50db4a959b3f50c2ff75e0b8bd5f5e038749e52a11",
@ -2757,7 +2757,112 @@
"0x568f44291c13efc908db42d2473bc91ebb16e062e9b4368bcb770a3033d67741",
"0xe5ecad510448855ff0aafb92a8c7aa54aca0fb390bec3c14ad5d2ba200380aec",
"0xa40aa7655c1458b76c04ea5934ae171fb01c72c8c375bb61a0c27b0ebd70f21f",
"0x770ad5107ac47fd983979b016553ca8f340a13e2647b9140e65c980dcf349cff"
"0x770ad5107ac47fd983979b016553ca8f340a13e2647b9140e65c980dcf349cff",
"0xfd074cacab08d2d5f113669672632ab0e94e03bfbbe17fc3de27a30e9f0e8327",
"0x2063bf5ce8eed483242157113534b314296deb123cb33083cb0cce04db610c9a",
"0x9dfb8274e842fd3cb7d73506e64adacc39eb12ebd8a972b7101385ac4eb5b12c",
"0x8294c3d4892cb0bcba9acdd31d53af5bfc97daf124f08d903297da8bbb28cdfe",
"0x9dc2d04fe197009f24ebd4a0c95a0b91d4ff0093387b61569af993fa91edb3fa",
"0xe88e256abdc6447b1f141c2fcf2c46721d9717a9fcb302513c93ed6e31b7c11c",
"0xd2ad4ca6091f6ae6c323b6565522c208a839e36958a1675e5e9b48b13068e7c8",
"0xb168169f2643b8cdbec58f3f94d7889af37117a35389726563ac770f5205faab",
"0x09f32b423ca728b8fd04f9872325c0e2a4c9b1eb36fab49b31ae51254c69ebab",
"0x0b47f8f28a3242c9ca705fd11949e648f190053de023366f98e6c736eb2f0de1",
"0x870a8067623b35b5f0146ec95047869357617fe3773a8285a622c18d44963f9f",
"0xd14e05d8f3238294ffd8885c1f1710f64f2d8eb3d3b4e8a921f7f5c94a0a6288",
"0xf9cdef6ffacbea7692e9fef3de1b778bd11399492486dca0209b27bd474eb04a",
"0x5dc41201eaa00957d070c68bb289fc00eb31b7e5fff52f0603d52d27a40abf81",
"0xae3a53054ff4e3e5562795b45777e1e3e82abeed84e2fab748af50aace8bc8e2",
"0x93fd6f9af3b1efd27487477edccd690b19902300a4eebd34cb0d9b2e60b3cccf",
"0xbe475a9dc045e70ac8218e5a65450edf026d70f3f814162251f83a88098245c2",
"0x20566435d247cc1e7d0d81e143c01b6649fa1fd3cd5a9f97738e6045b29460c5",
"0xb37273228fe8b0c1679bb2dab7176ee1282400daddaaeb0db415c716f5dd1f71",
"0x494bb2cea59fc43629b0f8be3fba9ee5b52948c72fd1f1c94d31600756bfb675",
"0xc690eb3d8e65d5efc211def8fe8f198e42c0321000b8998a6ab218d897d593a5",
"0x26821d73690b9d1bdd9594c92b086291474cd365bd41f7de5edc49dfc29c26df",
"0x026a57937338c9e168d254f99dc9dbe3fb41508049ac1a5b6d7df868e2935e6c",
"0x50dc451812556bd69244f3728c6a17e958b2fa125248103942ac94142610bcc7",
"0x0ffe7ea32c3ef43049d8041a16bd3381ba89b1439dc5329e839546aa01a64726",
"0xab1e06f13dbaed341fc9e33ef387ebbe187787ccd8961a47560f7e02617a06db",
"0x8b72166b0d16ebfd9c3156f5972e3778e16b3d7edf3decd4b6efbc779990ca3c",
"0x149de0dcdbe03bf6d0ae9ccc989a074a4cf2e78311ce8cb6dee3856c2a374caa",
"0x42147f5960814dc31cc38b692089e6d1d53b85cc85a69e4cc01954dc61c268a6",
"0x1460ceccff1ac00f3e126383c3102c424b75c2abeb973d0baa8bec8e7bdda692",
"0xdbbbf28a5d25c832c5f625868dea79a481dce880d5145f4119d3e9eb32356a6b",
"0xd8e5b32a88bdb502fbd62888b9906a0c7955ccaaad1ead31636572a07fe7419b",
"0xdbc42abbec7d223666da11767d9862cd1458f91b5bf2f6499da4ae5bff281888",
"0xc3138499753f545de139238bdc8cd4cbad254c6b87bf0eb37dc1fe7a85168e79",
"0x42be700f627bb081543ab289fcd01235bedea5e33a9779d6d14744685f5a652a",
"0x8660e4130c98f6a8024c1b587dd24ebe402126d4d9a2adf610c62bf033b749c5",
"0xdab926bab8c4ff9e492f992b5696e8f7e3ba3ce77e49fe0e2ca36d3efc8791b6",
"0x0e3911bcf379fd57014bee6a1f796b884c62f2392cf6e8ac5a145126e4622b88",
"0xbd52346714664eeb7b4034bc6a54804824bdd40d9e5bdbae9375a302926babe6",
"0x641e58eaeb404f7a40b9c4be686c26721563b310f7624a654185a60374c1512e",
"0xfa07b0f7b970413ae5085f042224861bb1bc5f2f6ad72a44c3681d47a817c0a9",
"0x70cf3fffa7e27f03d5cbb1664bbd0e1315dfc43df76f1b0e3dce494255e54752",
"0x1d5b0118939994aa8be89dc365f909309df84e7c92530aef25d62118b09e0572",
"0x8b34c5a5cd5a42a58bbc60166f3f2a4be7d79057691c708e7a9639c21b6f57c7",
"0x7b149005e7f8378189c70c33c073d897cb07f62ba5ae319088b3be204beea8e4",
"0xf2a41e8feb5d294faca47dd1f7a90f66b7b616addcd179ae60c5f173cd44a85d",
"0xa2875c8e5a226f2cf69f07e19b13a628ef6a8662f3a5de4c9d666ca5ebddb001",
"0x4231ca8bdccd59526900a487608912a4fc0918a6c693250bd67787bc61a9d09b",
"0x2b06301a6372e0fca0da8a15d4e31a08522ecb91efbda58c3e495e2ab7f4fceb",
"0xd0e19f62b07275097b56e7f409cd52826a1dbc0be26eeaae20562420559153dc",
"0xa4ecf1ef04bcc95ba0ed9214e9118129ae5497c37db94dda284dd536b4dd75c9",
"0x3dc87ba482aaac6b59678c899bfb1da9b768e1385e0f8e8574852efeee2db8c0",
"0x07f8df3f6ec63d926c3a76b17ad1750a9ac6c62a8cdffa549440e651f6087178",
"0x96952f8ba7c83d640119868a030cb7397624ef322b2d153aa3843259da5f468c",
"0x08eca2fb4295f069f3fa62849b354a9e10b8a8e9b771cb8d2790b28b7b09d70c",
"0xfd5832f531c8819c0ce9d031434c33eb442578e81cf711e8ba23e9b21d096e13",
"0xfee9a8bae124565c963b65fa47dcf7f0c9b5ef7e778c2d99539b8a04efd04522",
"0xead692739a0723a73dd38b3aa02f93d72b3b6922c2520ea0b74981eaafe7f6a1",
"0x890dd8befeee6c7c7b4942b02a3bf1a9d1b9e1140ecd1c07de570f38b6c323b6",
"0x690343489ed214b9195db6181c42237b7a62fc935a18ca1a5dc883a2045ceae7",
"0x4bdfdc1bef8c19b89344230c0f48841abfeea788a4973c34afff4d2039ce4417",
"0x6ef6a94338d794400f95f8c0b6d5a40df8b56c31e9bd0037bdd7e41234bb32a1",
"0x00b7568bfdf2d4780b8650a49f707752a12fe9a88302622e68f264622877acdc",
"0x83e96e0b864df30b53ae08075acc83f785e9b8b2bc80e8976b1a954f995df012",
"0x664305b610d0b3167dd25210acba7eea291a37a224546a6f6d59aa7b71d16e5f",
"0x3d3a6401ab83eabc2af15a23b9c0e6d123f661b3599c6131d5923a106f562ac8",
"0x7a11833fbc8ce3d9883088649b930238625e6f6136dfa06a00daf8e646cd020c",
"0x112c33932097c4ec4e18f6308b2a6502cbf746605f1e404555dd07703d60ba2d",
"0x9e77cd028749d69caf352a95f75dee842c0d9323e3618afa2927b2aaaf7fc4a8",
"0x7fe0a62bfd04e263b4c67c5808f6231ad6faca7ff0f5bc0c02177034608d6991",
"0xea820d62b423b68da2f8ce345dbb56e2205fdfae1fce261d64acc959fb30cccd",
"0xd8f6367448dec55e8e2e26b5d304d92969abde131d402de313b1705c0bfd528f",
"0x4b97f3b4e0bff7cfe322e4f50176f6bfb379a706d42308ae75b2a46735762a95",
"0x7425ff9cea5e4869332ce12ef727fbcb004add827eb567424fd4c17717def390",
"0xc7dcd4fd005ae8d4d9e125727b54a64e900b3fee9cdc82fb5057c012178c8483",
"0x8ba88bfba201db1db716f762b5517369d3ae232ca045d2932fc27f6c47b15806",
"0xad2f63fa4fddd0cfc7f6cb01116d285e8aad4b0c51fa9445d39a4cb4949ed020",
"0x366874aec4ea26ece424f5402604ec7df9f40fc4cb9087cd3f45e764b1e36ebf",
"0x7f27eb75010b0d5da72794c129042511e24794b6c8491c1ff2e257dadcc7052d",
"0x27eadc596f6eaeb9247704c3339f7fe4e649f683fd815f9d71270caf5d9e38cd",
"0xba3f72ce8f45b1575554bd0c64feda3959c2a68f0300f021b67880b56f7152e2",
"0x50833c82dc63533f7ec918cd6d58ffbef4e2d597f354589b8eb66c9de0fc9697",
"0x30fc354a8893f683ef03bb024254574b550710f3c05496976cd39166a29e1c98",
"0x1b6b8d13fca6583d358b173c1a255c3db9efed8ad72084eadf10e29868a26fdc",
"0xb1b2a80122d1210160d8649d31422a1edc26b23e8499aa3a88b047dc52b42222",
"0x4e6c85a13cc0c739fbdf844a4f52c78979a84a86db728e4a5d2043ee3b2fcb3e",
"0xe98c28b49aa690aecfa43527acd3e5a010c8f90faf79ef5b4b479a715fe66a99",
"0x5b56e2b50ec96f7bda3f529ed71321650d688e2ee5c16723f6199256532ee660",
"0x1c9b8f5106a23096f2f57dfdb2a7a82876f4374be97b6a818fdc3c742b216b09",
"0xcb6973f775356ec7596ed6f9a036258e98677c7c5b2358da75af28f553327506",
"0x26b42a54252893f59e8eca923a0d2f2c0fe507a680e8907e2904702791c42aea",
"0x25fec26921bb5b6cd9657588b09813270cad72947abc6cb2726764db44181ff2",
"0xdfbd186df632b63f4cf74db660c59e658e0b4b725fe244a563c6698dd94adaf4",
"0xd1e00635e2399f6fa625f5c204e4c1643a7b619271394141433d26d902479bbe",
"0x3d3323fea45851eb0bc0b6c80a79cc0d0582abd8032aba957e719c31bb7901e6",
"0xe7d7b4c68d4f55ea8b71b43ad20bdd86402d36b6360ed0ca18082942736a7e41",
"0x1436749eca0a72b74bf8d596e3499414d412fbea0b936ee3564c4f83de907092",
"0xa828c16af52bd4adcb64928fada82a02d0a49fd3f53c5083ca9acfd998f8af1d",
"0x0fe559ad45cde755dd41876c5a65a690d32fc3d294fafeaa43e3fe133ae48da8",
"0x8f91d2082e5a1e6c1c905936515ab5f03889ac67261ef1d892fd909a9379a8ba",
"0x3881a9fe4ba6a24dcfa86351be2ca741dc9b2078409b2e7e0140569f19733505",
"0x4a3295525bfdda29bb9a552d8dc5c992649699f5694f96ff5bb0647910386db2",
"0x337389b3e800bae87fdbe5271f2167f169ffeb4710ecdcea30f08b2cefba57b1",
"0x2978e1e3c2b5dfe0b41ceb5c9c4029f42d346a2123a199c52ba6efdbf1d5fb68",
"0x8abbdb4f1f88fe8900afdfe15f3d03244435d4fb871606a689c11f6420145b45"
]
},
"nodes": [

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -57,6 +57,12 @@ pub trait BlockProvider {
/// (though not necessarily a part of the canon chain).
fn is_known(&self, hash: &H256) -> bool;
/// Returns true if the given block is known and in the canon chain.
fn is_canon(&self, hash: &H256) -> bool {
let is_canon = || Some(hash == &self.block_hash(self.block_number(hash)?)?);
is_canon().unwrap_or(false)
}
/// Get the first block of the best part of the chain.
/// Return `None` if there is no gap and the first block is the genesis.
/// Any queries of blocks which precede this one are not guaranteed to
@ -148,7 +154,7 @@ pub trait BlockProvider {
fn blocks_with_bloom(&self, bloom: &Bloom, from_block: BlockNumber, to_block: BlockNumber) -> Vec<BlockNumber>;
/// Returns logs matching given filter.
fn logs<F>(&self, blocks: Vec<BlockNumber>, matches: F, limit: Option<usize>) -> Vec<LocalizedLogEntry>
fn logs<F>(&self, blocks: Vec<H256>, matches: F, limit: Option<usize>) -> Vec<LocalizedLogEntry>
where F: Fn(&LogEntry) -> bool + Send + Sync, Self: Sized;
}
@ -332,16 +338,18 @@ impl BlockProvider for BlockChain {
.collect()
}
fn logs<F>(&self, mut blocks: Vec<BlockNumber>, matches: F, limit: Option<usize>) -> Vec<LocalizedLogEntry>
/// Returns logs matching given filter. The order of logs returned will be the same as the order of the blocks
/// provided. And it's the callers responsibility to sort blocks provided in advance.
fn logs<F>(&self, mut blocks: Vec<H256>, matches: F, limit: Option<usize>) -> Vec<LocalizedLogEntry>
where F: Fn(&LogEntry) -> bool + Send + Sync, Self: Sized {
// sort in reverse order
blocks.sort_by(|a, b| b.cmp(a));
blocks.reverse();
let mut logs = blocks
.chunks(128)
.flat_map(move |blocks_chunk| {
blocks_chunk.into_par_iter()
.filter_map(|number| self.block_hash(*number).map(|hash| (*number, hash)))
.filter_map(|hash| self.block_number(&hash).map(|r| (r, hash)))
.filter_map(|(number, hash)| self.block_receipts(&hash).map(|r| (number, hash, r.receipts)))
.filter_map(|(number, hash, receipts)| self.block_body(&hash).map(|ref b| (number, hash, receipts, b.transaction_hashes())))
.flat_map(|(number, hash, mut receipts, mut hashes)| {
@ -368,7 +376,7 @@ impl BlockProvider for BlockChain {
.enumerate()
.map(move |(i, log)| LocalizedLogEntry {
entry: log,
block_hash: hash,
block_hash: *hash,
block_number: number,
transaction_hash: tx_hash,
// iterating in reverse order
@ -1933,17 +1941,33 @@ mod tests {
value: 103.into(),
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
}.sign(&secret(), None);
let t4 = Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 100_000.into(),
action: Action::Create,
value: 104.into(),
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
}.sign(&secret(), None);
let tx_hash1 = t1.hash();
let tx_hash2 = t2.hash();
let tx_hash3 = t3.hash();
let tx_hash4 = t4.hash();
let genesis = BlockBuilder::genesis();
let b1 = genesis.add_block_with_transactions(vec![t1, t2]);
let b2 = b1.add_block_with_transactions(iter::once(t3));
let b3 = genesis.add_block_with(|| BlockOptions {
transactions: vec![t4.clone()],
difficulty: U256::from(9),
..Default::default()
}); // Branch block
let b1_hash = b1.last().hash();
let b1_number = b1.last().number();
let b2_hash = b2.last().hash();
let b2_number = b2.last().number();
let b3_hash = b3.last().hash();
let b3_number = b3.last().number();
let db = new_db();
let bc = new_chain(&genesis.last().encoded(), db.clone());
@ -1974,10 +1998,21 @@ mod tests {
],
}
]);
insert_block(&db, &bc, &b3.last().encoded(), vec![
Receipt {
outcome: TransactionOutcome::StateRoot(H256::default()),
gas_used: 10_000.into(),
log_bloom: Default::default(),
logs: vec![
LogEntry { address: Default::default(), topics: vec![], data: vec![5], },
],
}
]);
// when
let logs1 = bc.logs(vec![1, 2], |_| true, None);
let logs2 = bc.logs(vec![1, 2], |_| true, Some(1));
let logs1 = bc.logs(vec![b1_hash, b2_hash], |_| true, None);
let logs2 = bc.logs(vec![b1_hash, b2_hash], |_| true, Some(1));
let logs3 = bc.logs(vec![b3_hash], |_| true, None);
// then
assert_eq!(logs1, vec![
@ -2029,6 +2064,17 @@ mod tests {
log_index: 0,
}
]);
assert_eq!(logs3, vec![
LocalizedLogEntry {
entry: LogEntry { address: Default::default(), topics: vec![], data: vec![5] },
block_hash: b3_hash,
block_number: b3_number,
transaction_hash: tx_hash4,
transaction_index: 0,
transaction_log_index: 0,
log_index: 0,
}
]);
}
#[test]

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::collections::{HashSet, HashMap, BTreeMap, VecDeque};
use std::collections::{HashSet, HashMap, BTreeMap, BTreeSet, VecDeque};
use std::str::FromStr;
use std::sync::{Arc, Weak};
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering};
@ -452,9 +452,7 @@ impl Importer {
///
/// The block is guaranteed to be the next best blocks in the
/// first block sequence. Does no sealing or transaction validation.
fn import_old_block(&self, block_bytes: Bytes, receipts_bytes: Bytes, db: &KeyValueDB, chain: &BlockChain) -> Result<H256, ::error::Error> {
let block = view!(BlockView, &block_bytes);
let header = block.header();
fn import_old_block(&self, header: &Header, block_bytes: Bytes, receipts_bytes: Bytes, db: &KeyValueDB, chain: &BlockChain) -> Result<H256, ::error::Error> {
let receipts = ::rlp::decode_list(&receipts_bytes);
let hash = header.hash();
let _import_lock = self.import_lock.lock();
@ -1413,7 +1411,7 @@ impl ImportBlock for Client {
use verification::queue::kind::blocks::Unverified;
// create unverified block here so the `keccak` calculation can be cached.
let unverified = Unverified::new(bytes);
let unverified = Unverified::from_rlp(bytes)?;
{
if self.chain.read().is_known(&unverified.hash()) {
@ -1428,19 +1426,19 @@ impl ImportBlock for Client {
}
fn import_block_with_receipts(&self, block_bytes: Bytes, receipts_bytes: Bytes) -> Result<H256, BlockImportError> {
let header: Header = ::rlp::Rlp::new(&block_bytes).val_at(0)?;
{
// check block order
let header = view!(BlockView, &block_bytes).header_view();
if self.chain.read().is_known(&header.hash()) {
bail!(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain));
}
let status = self.block_status(BlockId::Hash(header.parent_hash()));
if status == BlockStatus::Unknown || status == BlockStatus::Pending {
bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(header.parent_hash())));
let status = self.block_status(BlockId::Hash(*header.parent_hash()));
if status == BlockStatus::Unknown || status == BlockStatus::Pending {
bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(*header.parent_hash())));
}
}
self.importer.import_old_block(block_bytes, receipts_bytes, &**self.db.read(), &*self.chain.read()).map_err(Into::into)
self.importer.import_old_block(&header, block_bytes, receipts_bytes, &**self.db.read(), &*self.chain.read()).map_err(Into::into)
}
}
@ -1853,23 +1851,82 @@ impl BlockChainClient for Client {
}
fn logs(&self, filter: Filter) -> Vec<LocalizedLogEntry> {
let (from, to) = match (self.block_number_ref(&filter.from_block), self.block_number_ref(&filter.to_block)) {
(Some(from), Some(to)) => (from, to),
_ => return Vec::new(),
// Wrap the logic inside a closure so that we can take advantage of question mark syntax.
let fetch_logs = || {
let chain = self.chain.read();
// First, check whether `filter.from_block` and `filter.to_block` is on the canon chain. If so, we can use the
// optimized version.
let is_canon = |id| {
match id {
// If it is referred by number, then it is always on the canon chain.
&BlockId::Earliest | &BlockId::Latest | &BlockId::Number(_) => true,
// If it is referred by hash, we see whether a hash -> number -> hash conversion gives us the same
// result.
&BlockId::Hash(ref hash) => chain.is_canon(hash),
}
};
let blocks = if is_canon(&filter.from_block) && is_canon(&filter.to_block) {
// If we are on the canon chain, use bloom filter to fetch required hashes.
let from = self.block_number_ref(&filter.from_block)?;
let to = self.block_number_ref(&filter.to_block)?;
filter.bloom_possibilities().iter()
.map(|bloom| {
chain.blocks_with_bloom(bloom, from, to)
})
.flat_map(|m| m)
// remove duplicate elements
.collect::<BTreeSet<u64>>()
.into_iter()
.filter_map(|n| chain.block_hash(n))
.collect::<Vec<H256>>()
} else {
// Otherwise, we use a slower version that finds a link between from_block and to_block.
let from_hash = Self::block_hash(&chain, filter.from_block)?;
let from_number = chain.block_number(&from_hash)?;
let to_hash = Self::block_hash(&chain, filter.from_block)?;
let blooms = filter.bloom_possibilities();
let bloom_match = |header: &encoded::Header| {
blooms.iter().any(|bloom| header.log_bloom().contains_bloom(bloom))
};
let (blocks, last_hash) = {
let mut blocks = Vec::new();
let mut current_hash = to_hash;
loop {
let header = chain.block_header_data(&current_hash)?;
if bloom_match(&header) {
blocks.push(current_hash);
}
// Stop if `from` block is reached.
if header.number() <= from_number {
break;
}
current_hash = header.parent_hash();
}
blocks.reverse();
(blocks, current_hash)
};
// Check if we've actually reached the expected `from` block.
if last_hash != from_hash || blocks.is_empty() {
return None;
}
blocks
};
Some(self.chain.read().logs(blocks, |entry| filter.matches(entry), filter.limit))
};
let chain = self.chain.read();
let blocks = filter.bloom_possibilities().iter()
.map(move |bloom| {
chain.blocks_with_bloom(bloom, from, to)
})
.flat_map(|m| m)
// remove duplicate elements
.collect::<HashSet<u64>>()
.into_iter()
.collect::<Vec<u64>>();
self.chain.read().logs(blocks, |entry| filter.matches(entry), filter.limit)
fetch_logs().unwrap_or_default()
}
fn filter_traces(&self, filter: TraceFilter) -> Option<Vec<LocalizedTrace>> {

View File

@ -190,6 +190,7 @@ error_chain! {
foreign_links {
Block(BlockError) #[doc = "Block error"];
Decoder(::rlp::DecoderError) #[doc = "Rlp decoding error"];
}
errors {
@ -206,6 +207,7 @@ impl From<Error> for BlockImportError {
match e {
Error(ErrorKind::Block(block_error), _) => BlockImportErrorKind::Block(block_error).into(),
Error(ErrorKind::Import(import_error), _) => BlockImportErrorKind::Import(import_error.into()).into(),
Error(ErrorKind::Util(util_error::ErrorKind::Decoder(decoder_err)), _) => BlockImportErrorKind::Decoder(decoder_err).into(),
_ => BlockImportErrorKind::Other(format!("other block import error: {:?}", e)).into(),
}
}

View File

@ -21,7 +21,7 @@
use std::cell::{RefCell, RefMut};
use std::collections::hash_map::Entry;
use std::collections::{HashMap, BTreeMap, HashSet};
use std::collections::{HashMap, BTreeMap, BTreeSet, HashSet};
use std::fmt;
use std::sync::Arc;
use hash::{KECCAK_NULL_RLP, KECCAK_EMPTY};
@ -862,40 +862,65 @@ impl<B: Backend> State<B> {
}))
}
// Return a list of all touched addresses in cache.
fn touched_addresses(&self) -> Vec<Address> {
/// Populate a PodAccount map from this state, with another state as the account and storage query.
pub fn to_pod_diff<X: Backend>(&mut self, query: &State<X>) -> trie::Result<PodState> {
assert!(self.checkpoints.borrow().is_empty());
self.cache.borrow().iter().map(|(add, _)| *add).collect()
}
fn query_pod(&mut self, query: &PodState, touched_addresses: &[Address]) -> trie::Result<()> {
let pod = query.get();
// Merge PodAccount::to_pod for cache of self and `query`.
let all_addresses = self.cache.borrow().keys().cloned()
.chain(query.cache.borrow().keys().cloned())
.collect::<BTreeSet<_>>();
for address in touched_addresses {
if !self.ensure_cached(address, RequireCache::Code, true, |a| a.is_some())? {
continue
Ok(PodState::from(all_addresses.into_iter().fold(Ok(BTreeMap::new()), |m: trie::Result<_>, address| {
let mut m = m?;
let account = self.ensure_cached(&address, RequireCache::Code, true, |acc| {
acc.map(|acc| {
// Merge all modified storage keys.
let all_keys = {
let self_keys = acc.storage_changes().keys().cloned()
.collect::<BTreeSet<_>>();
if let Some(ref query_storage) = query.cache.borrow().get(&address)
.and_then(|opt| {
Some(opt.account.as_ref()?.storage_changes().keys().cloned()
.collect::<BTreeSet<_>>())
})
{
self_keys.union(&query_storage).cloned().collect::<Vec<_>>()
} else {
self_keys.into_iter().collect::<Vec<_>>()
}
};
// Storage must be fetched after ensure_cached to avoid borrow problem.
(*acc.balance(), *acc.nonce(), all_keys, acc.code().map(|x| x.to_vec()))
})
})?;
if let Some((balance, nonce, storage_keys, code)) = account {
let storage = storage_keys.into_iter().fold(Ok(BTreeMap::new()), |s: trie::Result<_>, key| {
let mut s = s?;
s.insert(key, self.storage_at(&address, &key)?);
Ok(s)
})?;
m.insert(address, PodAccount {
balance, nonce, storage, code
});
}
if let Some(pod_account) = pod.get(address) {
// needs to be split into two parts for the refcell code here
// to work.
for key in pod_account.storage.keys() {
self.storage_at(address, key)?;
}
}
}
Ok(())
Ok(m)
})?))
}
/// Returns a `StateDiff` describing the difference from `orig` to `self`.
/// Consumes self.
pub fn diff_from<X: Backend>(&self, orig: State<X>) -> trie::Result<StateDiff> {
let addresses_post = self.touched_addresses();
pub fn diff_from<X: Backend>(&self, mut orig: State<X>) -> trie::Result<StateDiff> {
let pod_state_post = self.to_pod();
let mut state_pre = orig;
state_pre.query_pod(&pod_state_post, &addresses_post)?;
Ok(pod_state::diff_pod(&state_pre.to_pod(), &pod_state_post))
let pod_state_pre = orig.to_pod_diff(self)?;
Ok(pod_state::diff_pod(&pod_state_pre, &pod_state_post))
}
// load required account data from the databases.
@ -2243,9 +2268,6 @@ mod tests {
let original = state.clone();
state.kill_account(&a);
assert_eq!(original.touched_addresses(), vec![]);
assert_eq!(state.touched_addresses(), vec![a]);
let diff = state.diff_from(original).unwrap();
let diff_map = diff.get();
assert_eq!(diff_map.len(), 1);
@ -2258,4 +2280,42 @@ mod tests {
storage: Default::default()
}), None).as_ref());
}
#[test]
fn should_trace_diff_unmodified_storage() {
use pod_account;
let a = 10.into();
let db = get_temp_state_db();
let (root, db) = {
let mut state = State::new(db, U256::from(0), Default::default());
state.set_storage(&a, H256::from(&U256::from(1u64)), H256::from(&U256::from(20u64))).unwrap();
state.commit().unwrap();
state.drop()
};
let mut state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
let original = state.clone();
state.set_storage(&a, H256::from(&U256::from(1u64)), H256::from(&U256::from(100u64))).unwrap();
let diff = state.diff_from(original).unwrap();
let diff_map = diff.get();
assert_eq!(diff_map.len(), 1);
assert!(diff_map.get(&a).is_some());
assert_eq!(diff_map.get(&a),
pod_account::diff_pod(Some(&PodAccount {
balance: U256::zero(),
nonce: U256::zero(),
code: Some(Default::default()),
storage: vec![(H256::from(&U256::from(1u64)), H256::from(&U256::from(20u64)))]
.into_iter().collect(),
}), Some(&PodAccount {
balance: U256::zero(),
nonce: U256::zero(),
code: Some(Default::default()),
storage: vec![(H256::from(&U256::from(1u64)), H256::from(&U256::from(100u64)))]
.into_iter().collect(),
})).as_ref());
}
}

View File

@ -36,6 +36,7 @@ use views::BlockView;
use ethkey::KeyPair;
use transaction::{PendingTransaction, Transaction, Action, Condition};
use miner::MinerService;
use rlp::{RlpStream, EMPTY_LIST_RLP};
use tempdir::TempDir;
#[test]
@ -111,6 +112,25 @@ fn imports_good_block() {
assert!(!block.into_inner().is_empty());
}
#[test]
fn fails_to_import_block_with_invalid_rlp() {
use error::{BlockImportError, BlockImportErrorKind};
let client = generate_dummy_client(6);
let mut rlp = RlpStream::new_list(3);
rlp.append_raw(&EMPTY_LIST_RLP, 1); // empty header
rlp.append_raw(&EMPTY_LIST_RLP, 1);
rlp.append_raw(&EMPTY_LIST_RLP, 1);
let invalid_header_block = rlp.out();
match client.import_block(invalid_header_block) {
Err(BlockImportError(BlockImportErrorKind::Decoder(_), _)) => (), // all good
Err(_) => panic!("Should fail with a decoder error"),
Ok(_) => panic!("Should not import block with invalid header"),
}
}
#[test]
fn query_none_block() {
let tempdir = TempDir::new("").unwrap();

View File

@ -119,14 +119,13 @@ pub mod blocks {
impl Unverified {
/// Create an `Unverified` from raw bytes.
pub fn new(bytes: Bytes) -> Self {
use views::BlockView;
pub fn from_rlp(bytes: Bytes) -> Result<Self, ::rlp::DecoderError> {
let header = view!(BlockView, &bytes).header();
Unverified {
let header = ::rlp::Rlp::new(&bytes).val_at(0)?;
Ok(Unverified {
header: header,
bytes: bytes,
}
})
}
}

View File

@ -734,6 +734,7 @@ mod tests {
use test_helpers::{get_good_dummy_block_seq, get_good_dummy_block};
use error::*;
use views::BlockView;
use bytes::Bytes;
// create a test block queue.
// auto_scaling enables verifier adjustment.
@ -746,6 +747,10 @@ mod tests {
BlockQueue::new(config, engine, IoChannel::disconnected(), true)
}
fn new_unverified(bytes: Bytes) -> Unverified {
Unverified::from_rlp(bytes).expect("Should be valid rlp")
}
#[test]
fn can_be_created() {
// TODO better test
@ -757,7 +762,7 @@ mod tests {
#[test]
fn can_import_blocks() {
let queue = get_test_queue(false);
if let Err(e) = queue.import(Unverified::new(get_good_dummy_block())) {
if let Err(e) = queue.import(new_unverified(get_good_dummy_block())) {
panic!("error importing block that is valid by definition({:?})", e);
}
}
@ -765,11 +770,11 @@ mod tests {
#[test]
fn returns_error_for_duplicates() {
let queue = get_test_queue(false);
if let Err(e) = queue.import(Unverified::new(get_good_dummy_block())) {
if let Err(e) = queue.import(new_unverified(get_good_dummy_block())) {
panic!("error importing block that is valid by definition({:?})", e);
}
let duplicate_import = queue.import(Unverified::new(get_good_dummy_block()));
let duplicate_import = queue.import(new_unverified(get_good_dummy_block()));
match duplicate_import {
Err(e) => {
match e {
@ -786,7 +791,7 @@ mod tests {
let queue = get_test_queue(false);
let block = get_good_dummy_block();
let hash = view!(BlockView, &block).header().hash().clone();
if let Err(e) = queue.import(Unverified::new(block)) {
if let Err(e) = queue.import(new_unverified(block)) {
panic!("error importing block that is valid by definition({:?})", e);
}
queue.flush();
@ -802,14 +807,14 @@ mod tests {
let queue = get_test_queue(false);
let block = get_good_dummy_block();
let hash = view!(BlockView, &block).header().hash().clone();
if let Err(e) = queue.import(Unverified::new(block)) {
if let Err(e) = queue.import(new_unverified(block)) {
panic!("error importing block that is valid by definition({:?})", e);
}
queue.flush();
queue.drain(10);
queue.mark_as_good(&[ hash ]);
if let Err(e) = queue.import(Unverified::new(get_good_dummy_block())) {
if let Err(e) = queue.import(new_unverified(get_good_dummy_block())) {
panic!("error importing block that has already been drained ({:?})", e);
}
}
@ -817,7 +822,7 @@ mod tests {
#[test]
fn returns_empty_once_finished() {
let queue = get_test_queue(false);
queue.import(Unverified::new(get_good_dummy_block()))
queue.import(new_unverified(get_good_dummy_block()))
.expect("error importing block that is valid by definition");
queue.flush();
queue.drain(1);
@ -835,7 +840,7 @@ mod tests {
assert!(!queue.queue_info().is_full());
let mut blocks = get_good_dummy_block_seq(50);
for b in blocks.drain(..) {
queue.import(Unverified::new(b)).unwrap();
queue.import(new_unverified(b)).unwrap();
}
assert!(queue.queue_info().is_full());
}
@ -863,7 +868,7 @@ mod tests {
*queue.state.0.lock() = State::Work(0);
for block in get_good_dummy_block_seq(5000) {
queue.import(Unverified::new(block)).expect("Block good by definition; qed");
queue.import(new_unverified(block)).expect("Block good by definition; qed");
}
// almost all unverified == bump verifier count.

View File

@ -476,7 +476,7 @@ mod tests {
unimplemented!()
}
fn logs<F>(&self, _blocks: Vec<BlockNumber>, _matches: F, _limit: Option<usize>) -> Vec<LocalizedLogEntry>
fn logs<F>(&self, _blocks: Vec<H256>, _matches: F, _limit: Option<usize>) -> Vec<LocalizedLogEntry>
where F: Fn(&LogEntry) -> bool, Self: Sized {
unimplemented!()
}

View File

@ -12,4 +12,4 @@ libc = "0.2"
pwasm-utils = "0.1"
vm = { path = "../vm" }
ethcore-logger = { path = "../../logger" }
wasmi = { version = "0.1.3", features = ["opt-in-32bit"] }
wasmi = { version = "0.2" }

View File

@ -33,7 +33,7 @@ use ethcore::snapshot::service::Service as SnapshotService;
use sync::{LightSyncProvider, LightSync, SyncProvider, ManageNetwork};
use io::{TimerToken, IoContext, IoHandler};
use light::Cache as LightDataCache;
use light::client::LightChainClient;
use light::client::{LightChainClient, LightChainNotify};
use number_prefix::{binary_prefix, Standalone, Prefixed};
use parity_rpc::{is_major_importing};
use parity_rpc::informant::RpcStats;
@ -395,6 +395,33 @@ impl ChainNotify for Informant<FullNodeInformantData> {
}
}
impl LightChainNotify for Informant<LightNodeInformantData> {
fn new_headers(&self, good: &[H256]) {
let mut last_import = self.last_import.lock();
let client = &self.target.client;
let importing = self.target.is_major_importing();
let ripe = Instant::now() > *last_import + Duration::from_secs(1) && !importing;
if ripe {
if let Some(header) = good.last().and_then(|h| client.block_header(BlockId::Hash(*h))) {
info!(target: "import", "Imported {} {} ({} Mgas){}",
Colour::White.bold().paint(format!("#{}", header.number())),
Colour::White.bold().paint(format!("{}", header.hash())),
Colour::Yellow.bold().paint(format!("{:.2}", header.gas_used().low_u64() as f32 / 1000000f32)),
if good.len() > 1 {
format!(" + another {} header(s)",
Colour::Red.bold().paint(format!("{}", good.len() - 1)))
} else {
String::new()
}
);
*last_import = Instant::now();
}
}
}
}
const INFO_TIMER: TimerToken = 0;
impl<T: InformantData> IoHandler<ClientIoMessage> for Informant<T> {

View File

@ -412,7 +412,7 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<Runnin
Some(rpc_stats),
cmd.logger_config.color,
));
service.add_notify(informant.clone());
service.register_handler(informant.clone()).map_err(|_| "Unable to register informant handler".to_owned())?;
Ok(RunningClient::Light {

View File

@ -309,11 +309,12 @@ case $BUILD_PLATFORM in
x86_64-unknown-snap-gnu)
ARC="amd64"
EXT="snap"
apt update
apt install -y expect zip rhash
snapcraft clean
echo "Prepare snapcraft.yaml for build on Gitlab CI in Docker image"
sed -i 's/git/'"$VER"'/g' snap/snapcraft.yaml
if [[ "$CI_BUILD_REF_NAME" = "beta" || "$VER" == *1.10* ]];
if [[ "$CI_BUILD_REF_NAME" = "beta" || "$VER" == *1.11* ]];
then
sed -i -e 's/grade: devel/grade: stable/' snap/snapcraft.yaml;
fi

View File

@ -105,10 +105,13 @@ pub struct NetworkContext<'s> {
impl<'s> NetworkContext<'s> {
/// Create a new network IO access point. Takes references to all the data that can be updated within the IO handler.
fn new(io: &'s IoContext<NetworkIoMessage>,
fn new(
io: &'s IoContext<NetworkIoMessage>,
protocol: ProtocolId,
session: Option<SharedSession>, sessions: Arc<RwLock<Slab<SharedSession>>>,
reserved_peers: &'s HashSet<NodeId>) -> NetworkContext<'s> {
session: Option<SharedSession>,
sessions: Arc<RwLock<Slab<SharedSession>>>,
reserved_peers: &'s HashSet<NodeId>,
) -> NetworkContext<'s> {
let id = session.as_ref().map(|s| s.lock().token());
NetworkContext {
io: io,
@ -585,10 +588,8 @@ impl Host {
let address = {
let mut nodes = self.nodes.write();
if let Some(node) = nodes.get_mut(id) {
node.attempts += 1;
node.endpoint.address
}
else {
} else {
debug!(target: "network", "Connection to expired node aborted");
return;
}
@ -600,6 +601,7 @@ impl Host {
},
Err(e) => {
debug!(target: "network", "{}: Can't connect to address {:?}: {:?}", id, address, e);
self.nodes.write().note_failure(&id);
return;
}
}
@ -685,10 +687,12 @@ impl Host {
Err(e) => {
let s = session.lock();
trace!(target: "network", "Session read error: {}:{:?} ({:?}) {:?}", token, s.id(), s.remote_addr(), e);
if let ErrorKind::Disconnect(DisconnectReason::IncompatibleProtocol) = *e.kind() {
if let ErrorKind::Disconnect(DisconnectReason::UselessPeer) = *e.kind() {
if let Some(id) = s.id() {
if !self.reserved_nodes.read().contains(id) {
self.nodes.write().mark_as_useless(id);
let mut nodes = self.nodes.write();
nodes.note_failure(&id);
nodes.mark_as_useless(id);
}
}
}
@ -754,6 +758,10 @@ impl Host {
}
}
}
// Note connection success
self.nodes.write().note_success(&id);
for (p, _) in self.handlers.read().iter() {
if s.have_capability(*p) {
ready_data.push(*p);
@ -1024,7 +1032,9 @@ impl IoHandler<NetworkIoMessage> for Host {
if let Some(session) = session {
session.lock().disconnect(io, DisconnectReason::DisconnectRequested);
if let Some(id) = session.lock().id() {
self.nodes.write().mark_as_useless(id)
let mut nodes = self.nodes.write();
nodes.note_failure(&id);
nodes.mark_as_useless(id);
}
}
trace!(target: "network", "Disabling peer {}", peer);

View File

@ -21,6 +21,8 @@ use std::net::{SocketAddr, ToSocketAddrs, SocketAddrV4, SocketAddrV6, Ipv4Addr,
use std::path::PathBuf;
use std::str::FromStr;
use std::{fs, mem, slice};
use std::time::{self, Duration, SystemTime};
use rand::{self, Rng};
use ethereum_types::H512;
use rlp::{Rlp, RlpStream, DecoderError};
use network::{Error, ErrorKind, AllowIP, IpFilter};
@ -128,40 +130,64 @@ impl FromStr for NodeEndpoint {
}
}
#[derive(PartialEq, Eq, Copy, Clone)]
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum PeerType {
_Required,
Optional
}
/// A type for representing an interaction (contact) with a node at a given time
/// that was either a success or a failure.
#[derive(Clone, Copy, Debug)]
pub enum NodeContact {
Success(SystemTime),
Failure(SystemTime),
}
impl NodeContact {
fn success() -> NodeContact {
NodeContact::Success(SystemTime::now())
}
fn failure() -> NodeContact {
NodeContact::Failure(SystemTime::now())
}
fn time(&self) -> SystemTime {
match *self {
NodeContact::Success(t) | NodeContact::Failure(t) => t
}
}
/// Filters and old contact, returning `None` if it happened longer than a
/// week ago.
fn recent(&self) -> Option<&NodeContact> {
let t = self.time();
if let Ok(d) = t.elapsed() {
if d < Duration::from_secs(60 * 60 * 24 * 7) {
return Some(self);
}
}
None
}
}
#[derive(Debug)]
pub struct Node {
pub id: NodeId,
pub endpoint: NodeEndpoint,
pub peer_type: PeerType,
pub attempts: u32,
pub failures: u32,
pub last_contact: Option<NodeContact>,
}
const DEFAULT_FAILURE_PERCENTAGE: usize = 50;
impl Node {
pub fn new(id: NodeId, endpoint: NodeEndpoint) -> Node {
Node {
id: id,
endpoint: endpoint,
peer_type: PeerType::Optional,
attempts: 0,
failures: 0,
}
}
/// Returns the node's failure percentage (0..100) in buckets of 5%. If there are 0 connection attempts for this
/// node the default failure percentage is returned (50%).
pub fn failure_percentage(&self) -> usize {
if self.attempts == 0 {
DEFAULT_FAILURE_PERCENTAGE
} else {
(self.failures * 100 / self.attempts / 5 * 5) as usize
last_contact: None,
}
}
}
@ -191,8 +217,7 @@ impl FromStr for Node {
id: id,
endpoint: endpoint,
peer_type: PeerType::Optional,
attempts: 0,
failures: 0,
last_contact: None,
})
}
}
@ -231,28 +256,61 @@ impl NodeTable {
/// Add a node to table
pub fn add_node(&mut self, mut node: Node) {
// preserve attempts and failure counter
let (attempts, failures) =
self.nodes.get(&node.id).map_or((0, 0), |n| (n.attempts, n.failures));
node.attempts = attempts;
node.failures = failures;
// preserve node last_contact
node.last_contact = self.nodes.get(&node.id).and_then(|n| n.last_contact);
self.nodes.insert(node.id.clone(), node);
}
/// Returns a list of ordered nodes according to their most recent contact
/// and filtering useless nodes. The algorithm for creating the sorted nodes
/// is:
/// - Contacts that aren't recent (older than 1 week) are discarded
/// - (1) Nodes with a successful contact are ordered (most recent success first)
/// - (2) Nodes with unknown contact (older than 1 week or new nodes) are randomly shuffled
/// - (3) Nodes with a failed contact are ordered (oldest failure first)
/// - The final result is the concatenation of (1), (2) and (3)
fn ordered_entries(&self) -> Vec<&Node> {
let mut refs: Vec<&Node> = self.nodes.values()
.filter(|n| !self.useless_nodes.contains(&n.id))
.collect();
let mut success = Vec::new();
let mut failures = Vec::new();
let mut unknown = Vec::new();
refs.sort_by(|a, b| {
a.failure_percentage().cmp(&b.failure_percentage())
.then_with(|| a.failures.cmp(&b.failures))
.then_with(|| b.attempts.cmp(&a.attempts)) // we use reverse ordering for number of attempts
let nodes = self.nodes.values()
.filter(|n| !self.useless_nodes.contains(&n.id));
for node in nodes {
// discard contact points older that aren't recent
match node.last_contact.as_ref().and_then(|c| c.recent()) {
Some(&NodeContact::Success(_)) => {
success.push(node);
},
Some(&NodeContact::Failure(_)) => {
failures.push(node);
},
None => {
unknown.push(node);
},
}
}
success.sort_by(|a, b| {
let a = a.last_contact.expect("vector only contains values with defined last_contact; qed");
let b = b.last_contact.expect("vector only contains values with defined last_contact; qed");
// inverse ordering, most recent successes come first
b.time().cmp(&a.time())
});
refs
failures.sort_by(|a, b| {
let a = a.last_contact.expect("vector only contains values with defined last_contact; qed");
let b = b.last_contact.expect("vector only contains values with defined last_contact; qed");
// normal ordering, most distant failures come first
a.time().cmp(&b.time())
});
rand::thread_rng().shuffle(&mut unknown);
success.append(&mut unknown);
success.append(&mut failures);
success
}
/// Returns node ids sorted by failure percentage, for nodes with the same failure percentage the absolute number of
@ -296,10 +354,17 @@ impl NodeTable {
}
}
/// Increase failure counte for a node
/// Set last contact as failure for a node
pub fn note_failure(&mut self, id: &NodeId) {
if let Some(node) = self.nodes.get_mut(id) {
node.failures += 1;
node.last_contact = Some(NodeContact::failure());
}
}
/// Set last contact as success for a node
pub fn note_success(&mut self, id: &NodeId) {
if let Some(node) = self.nodes.get_mut(id) {
node.last_contact = Some(NodeContact::success());
}
}
@ -396,19 +461,38 @@ mod json {
pub nodes: Vec<Node>,
}
#[derive(Serialize, Deserialize)]
pub enum NodeContact {
#[serde(rename = "success")]
Success(u64),
#[serde(rename = "failure")]
Failure(u64),
}
impl NodeContact {
pub fn into_node_contact(self) -> super::NodeContact {
match self {
NodeContact::Success(s) => super::NodeContact::Success(
time::UNIX_EPOCH + Duration::from_secs(s)
),
NodeContact::Failure(s) => super::NodeContact::Failure(
time::UNIX_EPOCH + Duration::from_secs(s)
),
}
}
}
#[derive(Serialize, Deserialize)]
pub struct Node {
pub url: String,
pub attempts: u32,
pub failures: u32,
pub last_contact: Option<NodeContact>,
}
impl Node {
pub fn into_node(self) -> Option<super::Node> {
match super::Node::from_str(&self.url) {
Ok(mut node) => {
node.attempts = self.attempts;
node.failures = self.failures;
node.last_contact = self.last_contact.map(|c| c.into_node_contact());
Some(node)
},
_ => None,
@ -418,10 +502,18 @@ mod json {
impl<'a> From<&'a super::Node> for Node {
fn from(node: &'a super::Node) -> Self {
let last_contact = node.last_contact.and_then(|c| {
match c {
super::NodeContact::Success(t) =>
t.duration_since(time::UNIX_EPOCH).ok().map(|d| NodeContact::Success(d.as_secs())),
super::NodeContact::Failure(t) =>
t.duration_since(time::UNIX_EPOCH).ok().map(|d| NodeContact::Failure(d.as_secs())),
}
});
Node {
url: format!("{}", node),
attempts: node.attempts,
failures: node.failures,
last_contact
}
}
}
@ -464,42 +556,54 @@ mod tests {
}
#[test]
fn table_failure_percentage_order() {
fn table_last_contact_order() {
let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap();
let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap();
let node3 = Node::from_str("enode://c979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap();
let node4 = Node::from_str("enode://d979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap();
let node5 = Node::from_str("enode://e979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap();
let node6 = Node::from_str("enode://f979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap();
let id1 = H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
let id2 = H512::from_str("b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
let id3 = H512::from_str("c979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
let id4 = H512::from_str("d979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
let id5 = H512::from_str("e979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
let id6 = H512::from_str("f979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
let mut table = NodeTable::new(None);
table.add_node(node1);
table.add_node(node2);
table.add_node(node3);
table.add_node(node4);
table.add_node(node5);
table.add_node(node6);
// node 1 - failure percentage 100%
table.get_mut(&id1).unwrap().attempts = 2;
// failures - nodes 1 & 2
table.note_failure(&id1);
table.note_failure(&id1);
// node2 - failure percentage 33%
table.get_mut(&id2).unwrap().attempts = 3;
table.note_failure(&id2);
// node3 - failure percentage 0%
table.get_mut(&id3).unwrap().attempts = 1;
// success - nodes 3 & 4
table.note_success(&id3);
table.note_success(&id4);
// node4 - failure percentage 50% (default when no attempts)
// success - node 5 (old contact)
table.get_mut(&id5).unwrap().last_contact = Some(NodeContact::Success(time::UNIX_EPOCH));
// unknown - node 6
let r = table.nodes(IpFilter::default());
assert_eq!(r[0][..], id3[..]);
assert_eq!(r[1][..], id2[..]);
assert_eq!(r[2][..], id4[..]);
assert_eq!(r[3][..], id1[..]);
assert_eq!(r[0][..], id4[..]); // most recent success
assert_eq!(r[1][..], id3[..]);
// unknown (old contacts and new nodes), randomly shuffled
assert!(
r[2][..] == id5[..] && r[3][..] == id6[..] ||
r[2][..] == id6[..] && r[3][..] == id5[..]
);
assert_eq!(r[4][..], id1[..]); // oldest failure
assert_eq!(r[5][..], id2[..]);
}
#[test]
@ -507,23 +611,27 @@ mod tests {
let tempdir = TempDir::new("").unwrap();
let node1 = Node::from_str("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap();
let node2 = Node::from_str("enode://b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap();
let node3 = Node::from_str("enode://c979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@22.99.55.44:7770").unwrap();
let id1 = H512::from_str("a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
let id2 = H512::from_str("b979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
let id3 = H512::from_str("c979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c").unwrap();
{
let mut table = NodeTable::new(Some(tempdir.path().to_str().unwrap().to_owned()));
table.add_node(node1);
table.add_node(node2);
table.add_node(node3);
table.get_mut(&id1).unwrap().attempts = 1;
table.get_mut(&id2).unwrap().attempts = 1;
table.note_failure(&id2);
table.note_success(&id2);
table.note_failure(&id3);
}
{
let table = NodeTable::new(Some(tempdir.path().to_str().unwrap().to_owned()));
let r = table.nodes(IpFilter::default());
assert_eq!(r[0][..], id1[..]);
assert_eq!(r[1][..], id2[..]);
assert_eq!(r[0][..], id2[..]); // latest success
assert_eq!(r[1][..], id1[..]); // unknown
assert_eq!(r[2][..], id3[..]); // oldest failure
}
}

View File

@ -10,7 +10,7 @@ build = "build.rs"
[package.metadata]
# This versions track. Should be changed to `stable` or `beta` when on respective branches.
# Used by auto-updater and for Parity version string.
track = "nightly"
track = "beta"
# Indicates a critical release in this track (i.e. consensus issue)
critical = true