diff --git a/.gitignore b/.gitignore index b22c1b842bb..53c0e8ac65f 100644 --- a/.gitignore +++ b/.gitignore @@ -38,7 +38,7 @@ node_modules # Build artifacts out/ -parity-clib-example/build/ +parity-clib-examples/cpp/build/ .vscode rls/ diff --git a/CHANGELOG.md b/CHANGELOG.md index c1494555616..467c0780248 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,113 @@ +## Parity [v1.11.6](https://github.com/paritytech/parity/releases/tag/v1.11.6) (2018-07-09) + +Parity 1.11.6 is a bug-fix release to improve performance and stability. + +The full list of included changes: + +- Beta: 1.11.6 backports ([#9015](https://github.com/paritytech/parity/pull/9015)) + - Parity-version: bump beta to 1.11.6 + - Scripts: remove md5 checksums ([#8884](https://github.com/paritytech/parity/pull/8884)) + - Add support for --chain tobalaba + - Convert indents to tabs :) + - Fixes for misbehavior reporting in AuthorityRound ([#8998](https://github.com/paritytech/parity/pull/8998)) + - Aura: only report after checking for repeated skipped primaries + - Aura: refactor duplicate code for getting epoch validator set + - Aura: verify_external: report on validator set contract instance + - Aura: use correct validator set epoch number when reporting + - Aura: use epoch set when verifying blocks + - Aura: report skipped primaries when generating seal + - Aura: handle immediate transitions + - Aura: don't report skipped steps from genesis to first block + - Aura: fix reporting test + - Aura: refactor duplicate code to handle immediate_transitions + - Aura: let reporting fail on verify_block_basic + - Aura: add comment about possible failure of reporting + - Only return error log for rustls ([#9025](https://github.com/paritytech/parity/pull/9025)) + - Transaction Pool improvements ([#8470](https://github.com/paritytech/parity/pull/8470)) + - Don't use ethereum_types in transaction pool. + - Hide internal insertion_id. + - Fix tests. + - Review grumbles. + - Improve should_replace on NonceAndGasPrice ([#8980](https://github.com/paritytech/parity/pull/8980)) + - Additional tests for NonceAndGasPrice::should_replace. + - Fix should_replace in the distinct sender case. + - Use natural priority ordering to simplify should_replace. + - Minimal effective gas price in the queue ([#8934](https://github.com/paritytech/parity/pull/8934)) + - Minimal effective gas price. + - Fix naming, add test + - Fix minimal entry score and add test. + - Fix worst_transaction. + - Remove effective gas price threshold. + - Don't leak gas_price decisions out of Scoring. + - Never drop local transactions from different senders. ([#9002](https://github.com/paritytech/parity/pull/9002)) + - Recently rejected cache for transaction queue ([#9005](https://github.com/paritytech/parity/pull/9005)) + - Store recently rejected transactions. + - Don't cache AlreadyImported rejections. + - Make the size of transaction verification queue dependent on pool size. + - Add a test for recently rejected. + - Fix logging for recently rejected. + - Make rejection cache smaller. + - Obsolete test removed + - Obsolete test removed + - Construct cache with_capacity. + - Optimize pending transactions filter ([#9026](https://github.com/paritytech/parity/pull/9026)) + - Rpc: return unordered transactions in pending transactions filter + - Ethcore: use LruCache for nonce cache + - Only clear the nonce cache when a block is retracted + - Revert "ethcore: use LruCache for nonce cache" + - This reverts commit b382c19. + - Use only cached nonces when computing pending hashes. + - Give filters their own locks, so that they don't block one another. + - Fix pending transaction count if not sealing. + - Clear cache only when block is enacted. + - Fix RPC tests. + - Address review comments. + - A last bunch of txqueue performance optimizations ([#9024](https://github.com/paritytech/parity/pull/9024)) + - Clear cache only when block is enacted. + - Add tracing for cull. + - Cull split. + - Cull after creating pending block. + - Add constant, remove sync::read tracing. + - Reset debug. + - Remove excessive tracing. + - Use struct for NonceCache. + - Fix build + - Remove warnings. + - Fix build again. + - Miner: add missing macro use for trace_time + - Ci: remove md5 merge leftovers + +## Parity [v1.11.5](https://github.com/paritytech/parity/releases/tag/v1.11.5) (2018-06-29) + +Parity 1.11.5 is a bug-fix release to improve performance and stability. + +The full list of included changes: + +- Bump beta to 1.11.5 / Backports ([#8955](https://github.com/paritytech/parity/pull/8955)) + - Parity-version: bump beta to 1.11.5 + - Update ropsten.json ([#8926](https://github.com/paritytech/parity/pull/8926)) + - Update hardcoded headers ([#8925](https://github.com/paritytech/parity/pull/8925)) + - Update kovan.json + - Update Kovan to block 7693549 + - Update foundation.json + - Updated to block 5812225 + - Update ropsten.json + - Update to 3465217 + - Scripts: minor improvements ([#8930](https://github.com/paritytech/parity/pull/8930)) + - CI: enable 'latest' docker tag on master pipeline + - CI: mark both beta and stable as stable snap. + - CI: sign all windows binaries + - Scripts: fix docker build tag on latest using master ([#8952](https://github.com/paritytech/parity/pull/8952)) + - Rpc: cap gas limit of local calls ([#8943](https://github.com/paritytech/parity/pull/8943)) + - Snap: downgrade rust to revision 1.26.2, ref snapcraft/+bug/1778530 ([#8984](https://github.com/paritytech/parity/pull/8984)) + - Snap: downgrade rust to revision 1.26.2, ref snapcraft/+bug/1778530 + - Snap: use plugin rust + - Fix deadlock in blockchain. ([#8977](https://github.com/paritytech/parity/pull/8977)) + - Remove js-glue from workspace + - This fixes test error on Rust 1.27 but also prevents js-glue from building itself. + - Builtin dapp users can still use js-glue from crates.io. + - Fix Android build on beta ([#9003](https://github.com/paritytech/parity/pull/9003)) + ## Parity [v1.11.4](https://github.com/paritytech/parity/releases/tag/v1.11.4) (2018-06-20) Parity 1.11.4 is a bug-fix release to improve performance and stability. diff --git a/Cargo.lock b/Cargo.lock index e97180bb284..c791ae4a925 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,7 +75,7 @@ name = "backtrace-sys" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -156,7 +156,7 @@ version = "0.1.0" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethbloom 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -191,7 +191,7 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.10" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -384,11 +384,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "dir" -version = "0.1.0" +version = "0.1.1" dependencies = [ "app_dirs 1.2.1 (git+https://github.com/paritytech/app-dirs-rs)", + "dirs 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "journaldb 0.1.0", + "journaldb 0.2.0", +] + +[[package]] +name = "dirs" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -435,6 +445,18 @@ dependencies = [ "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "env_logger" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "error-chain" version = "0.11.0" @@ -457,7 +479,7 @@ version = "0.5.7" source = "git+https://github.com/paritytech/rust-secp256k1#db81cfea59014b4d176f10f86ed52e1a130b6822" dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -500,7 +522,7 @@ dependencies = [ "keccak-hash 0.1.2", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "primal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -546,13 +568,13 @@ dependencies = [ "ethstore 0.2.0", "evm 0.1.0", "fake-hardware-wallet 0.0.1", - "fetch 0.1.0", "hardware-wallet 1.12.0", - "hashdb 0.1.1", + "hashdb 0.2.0", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "journaldb 0.1.0", + "journaldb 0.2.0", "keccak-hash 0.1.2", + "keccak-hasher 0.1.0", "kvdb 0.1.0", "kvdb-memorydb 0.1.0", "kvdb-rocksdb 0.1.0", @@ -561,12 +583,13 @@ dependencies = [ "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "macros 0.1.0", "memory-cache 0.1.0", - "memorydb 0.1.1", + "memorydb 0.2.0", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-machine 0.1.0", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "patricia-trie 0.1.0", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "patricia-trie 0.2.0", + "patricia-trie-ethereum 0.1.0", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", @@ -582,7 +605,6 @@ dependencies = [ "triehash 0.1.0", "unexpected 0.1.0", "using_queue 0.1.0", - "util-error 0.1.0", "vm 0.1.0", "wasm 0.1.0", ] @@ -622,7 +644,7 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", "timer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -641,18 +663,20 @@ dependencies = [ "ethcore-transaction 0.1.0", "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "hashdb 0.1.1", + "hashdb 0.2.0", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.2", + "keccak-hasher 0.1.0", "kvdb 0.1.0", "kvdb-memorydb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "memory-cache 0.1.0", - "memorydb 0.1.1", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "patricia-trie 0.1.0", - "plain_hasher 0.1.0", + "memorydb 0.2.0", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "patricia-trie 0.2.0", + "patricia-trie-ethereum 0.1.0", + "plain_hasher 0.2.0", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", "rlp_derive 0.1.0", @@ -675,7 +699,7 @@ dependencies = [ "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -700,7 +724,7 @@ dependencies = [ "linked-hash-map 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "parity-reactor 0.1.0", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "price-info 1.12.0", "rlp 0.2.1", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -746,8 +770,8 @@ 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)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "path 0.1.0", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "path 0.1.1", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", @@ -783,8 +807,9 @@ dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.2", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "patricia-trie 0.1.0", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "patricia-trie 0.2.0", + "patricia-trie-ethereum 0.1.0", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", "rlp_derive 0.1.0", @@ -820,7 +845,7 @@ dependencies = [ "kvdb-rocksdb 0.1.0", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", @@ -865,7 +890,7 @@ dependencies = [ "jsonrpc-tcp-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "keccak-hash 0.1.2", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -885,15 +910,17 @@ dependencies = [ "ethcore-transaction 0.1.0", "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", + "hashdb 0.2.0", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.2", + "keccak-hasher 0.1.0", "kvdb 0.1.0", "kvdb-memorydb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "macros 0.1.0", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "plain_hasher 0.1.0", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "plain_hasher 0.2.0", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -991,7 +1018,7 @@ dependencies = [ name = "ethstore" version = "0.2.0" dependencies = [ - "dir 0.1.0", + "dir 0.1.1", "ethcore-crypto 0.1.0", "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", @@ -1000,7 +1027,7 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1016,12 +1043,12 @@ dependencies = [ name = "ethstore-cli" version = "0.1.0" dependencies = [ - "dir 0.1.0", + "dir 0.1.1", "docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethstore 0.2.0", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "panic_hook 0.1.0", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1039,7 +1066,7 @@ dependencies = [ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "memory-cache 0.1.0", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "vm 0.1.0", ] @@ -1095,11 +1122,11 @@ version = "0.1.0" dependencies = [ "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1135,10 +1162,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "fs-swap" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1170,14 +1199,6 @@ dependencies = [ "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "futures-timer" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "gcc" version = "0.3.54" @@ -1219,7 +1240,7 @@ dependencies = [ "hidapi 0.3.1 (git+https://github.com/paritytech/hidapi-rs)", "libusb 0.3.0 (git+https://github.com/paritytech/libusb-rs)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "protobuf 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1228,10 +1249,10 @@ dependencies = [ [[package]] name = "hashdb" -version = "0.1.1" +version = "0.2.0" dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1260,7 +1281,7 @@ name = "hidapi" version = "0.3.1" source = "git+https://github.com/paritytech/hidapi-rs#70ec4bd1b755ec5dd32ad2be0c8345864147c8bc" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1269,6 +1290,14 @@ name = "httparse" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "humantime" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "hyper" version = "0.11.24" @@ -1375,28 +1404,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "journaldb" -version = "0.1.0" +version = "0.2.0" dependencies = [ "ethcore-bytes 0.1.0", "ethcore-logger 1.12.0", "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hashdb 0.1.1", + "hashdb 0.2.0", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.2", + "keccak-hasher 0.1.0", "kvdb 0.1.0", "kvdb-memorydb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "memorydb 0.1.1", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "plain_hasher 0.1.0", + "memorydb 0.2.0", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "plain_hasher 0.2.0", "rlp 0.2.1", - "util-error 0.1.0", ] [[package]] name = "jsonrpc-core" version = "8.0.1" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#c8e6336798be4444953def351099078617d40efd" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#6b972b5fd34ada4a7de6aed1a8c92475a907732d" dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1408,7 +1437,7 @@ dependencies = [ [[package]] name = "jsonrpc-http-server" version = "8.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#c8e6336798be4444953def351099078617d40efd" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#6b972b5fd34ada4a7de6aed1a8c92475a907732d" dependencies = [ "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", @@ -1421,7 +1450,7 @@ dependencies = [ [[package]] name = "jsonrpc-ipc-server" version = "8.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#c8e6336798be4444953def351099078617d40efd" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#6b972b5fd34ada4a7de6aed1a8c92475a907732d" dependencies = [ "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-server-utils 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", @@ -1433,7 +1462,7 @@ dependencies = [ [[package]] name = "jsonrpc-macros" version = "8.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#c8e6336798be4444953def351099078617d40efd" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#6b972b5fd34ada4a7de6aed1a8c92475a907732d" dependencies = [ "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-pubsub 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", @@ -1443,17 +1472,17 @@ dependencies = [ [[package]] name = "jsonrpc-pubsub" version = "8.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#c8e6336798be4444953def351099078617d40efd" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#6b972b5fd34ada4a7de6aed1a8c92475a907732d" dependencies = [ "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "jsonrpc-server-utils" version = "8.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#c8e6336798be4444953def351099078617d40efd" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#6b972b5fd34ada4a7de6aed1a8c92475a907732d" dependencies = [ "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "globset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1466,25 +1495,25 @@ dependencies = [ [[package]] name = "jsonrpc-tcp-server" version = "8.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#c8e6336798be4444953def351099078617d40efd" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#6b972b5fd34ada4a7de6aed1a8c92475a907732d" dependencies = [ "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-server-utils 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "jsonrpc-ws-server" version = "8.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#c8e6336798be4444953def351099078617d40efd" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#6b972b5fd34ada4a7de6aed1a8c92475a907732d" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-server-utils 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "ws 0.7.5 (git+https://github.com/tomusdrw/ws-rs)", ] @@ -1498,6 +1527,16 @@ dependencies = [ "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "keccak-hasher" +version = "0.1.0" +dependencies = [ + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hashdb 0.2.0", + "plain_hasher 0.2.0", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -1520,7 +1559,7 @@ name = "kvdb-memorydb" version = "0.1.0" dependencies = [ "kvdb 0.1.0", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1529,12 +1568,12 @@ version = "0.1.0" dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "fs-swap 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "fs-swap 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "interleaved-ordered 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "kvdb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rocksdb 0.4.5 (git+https://github.com/paritytech/rust-rocksdb)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1565,6 +1604,15 @@ name = "libc" version = "0.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "libloading" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "libusb" version = "0.3.0" @@ -1580,7 +1628,7 @@ name = "libusb-sys" version = "0.2.4" source = "git+https://github.com/paritytech/libusb-sys#14bdb698003731b6344a79e1d814704e44363e7c" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1604,6 +1652,15 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lock_api" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "log" version = "0.3.9" @@ -1678,15 +1735,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "memorydb" -version = "0.1.1" +version = "0.2.0" dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hashdb 0.1.1", + "hashdb 0.2.0", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.2", - "plain_hasher 0.1.0", + "keccak-hasher 0.1.0", + "plain_hasher 0.2.0", "rlp 0.2.1", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1733,7 +1792,7 @@ name = "miniz_oxide_c_api" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "miniz_oxide 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1855,7 +1914,7 @@ dependencies = [ "kvdb-memorydb 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1868,7 +1927,7 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "ntp 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-reactor 0.1.0", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2013,7 +2072,7 @@ dependencies = [ "clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)", "ctrlc 1.1.1 (git+https://github.com/paritytech/rust-ctrlc.git)", "daemonize 0.2.3 (git+https://github.com/paritytech/daemonize)", - "dir 0.1.0", + "dir 0.1.1", "docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.12.0", @@ -2035,7 +2094,7 @@ dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", - "journaldb 0.1.0", + "journaldb 0.2.0", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "keccak-hash 0.1.2", "kvdb 0.1.0", @@ -2058,8 +2117,8 @@ dependencies = [ "parity-updater 1.12.0", "parity-version 1.12.0", "parity-whisper 0.1.0", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "path 0.1.0", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "path 0.1.1", "pretty_assertions 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "registrar 0.0.1", @@ -2110,7 +2169,7 @@ dependencies = [ "parity-hash-fetch 1.12.0", "parity-reactor 0.1.0", "parity-version 1.12.0", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "registrar 0.0.1", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2154,7 +2213,7 @@ dependencies = [ "mime 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "mime_guess 2.0.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)", "parity-reactor 0.1.0", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "registrar 0.0.1", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2253,8 +2312,8 @@ dependencies = [ "parity-reactor 0.1.0", "parity-updater 1.12.0", "parity-version 1.12.0", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "patricia-trie 0.1.0", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "patricia-trie 0.2.0", "pretty_assertions 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", @@ -2283,7 +2342,7 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-rpc 1.12.0", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2323,8 +2382,8 @@ dependencies = [ "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-hash-fetch 1.12.0", "parity-version 1.12.0", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "path 0.1.0", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "path 0.1.1", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2345,12 +2404,10 @@ dependencies = [ [[package]] name = "parity-wasm" -version = "0.27.5" +version = "0.31.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)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2370,7 +2427,7 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mem 0.1.0", "ordered-float 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2393,10 +2450,10 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.5.4" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot_core 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2417,26 +2474,45 @@ dependencies = [ [[package]] name = "path" -version = "0.1.0" +version = "0.1.1" +dependencies = [ + "dirs 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "patricia-trie" -version = "0.1.0" +version = "0.2.0" dependencies = [ "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bytes 0.1.0", - "ethcore-logger 1.12.0", "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hashdb 0.1.1", + "hashdb 0.2.0", + "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.1.2", + "keccak-hasher 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "memorydb 0.1.1", + "memorydb 0.2.0", + "patricia-trie-ethereum 0.1.0", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.1", "trie-standardmap 0.1.0", "triehash 0.1.0", ] +[[package]] +name = "patricia-trie-ethereum" +version = "0.1.0" +dependencies = [ + "elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethcore-bytes 0.1.0", + "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hashdb 0.2.0", + "keccak-hasher 0.1.0", + "patricia-trie 0.2.0", + "rlp 0.2.1", +] + [[package]] name = "percent-encoding" version = "1.0.0" @@ -2488,10 +2564,11 @@ dependencies = [ [[package]] name = "plain_hasher" -version = "0.1.0" +version = "0.2.0" dependencies = [ "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hashdb 0.2.0", ] [[package]] @@ -2517,7 +2594,7 @@ dependencies = [ "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2602,16 +2679,12 @@ dependencies = [ [[package]] name = "pwasm-utils" -version = "0.1.5" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (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)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-wasm 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2720,11 +2793,31 @@ dependencies = [ "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "regex" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "regex-syntax" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "regex-syntax" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "registrar" version = "0.0.1" @@ -2747,9 +2840,9 @@ dependencies = [ [[package]] name = "ring" version = "0.12.1" -source = "git+https://github.com/paritytech/ring#b98d7f586c0467d68e9946a5f47b4a04b9a86b4a" +source = "git+https://github.com/paritytech/ring#bae475e9f7ea7dd4ae671bef4b576089a9b06731" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2800,7 +2893,7 @@ name = "rocksdb-sys" version = "0.3.0" source = "git+https://github.com/paritytech/rust-rocksdb#ecf06adf3148ab10f6f7686b724498382ff4f36e" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "local-encoding 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "snappy-sys 0.1.0 (git+https://github.com/paritytech/rust-snappy)", @@ -3036,7 +3129,7 @@ name = "snappy-sys" version = "0.1.0" source = "git+https://github.com/paritytech/rust-snappy#40ac9a0d9fd613e7f38df800a11a589b7296da73" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3173,6 +3266,14 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "termcolor" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "termion" version = "1.5.1" @@ -3505,6 +3606,11 @@ dependencies = [ "trie-standardmap 0.1.0", ] +[[package]] +name = "ucd-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "uint" version = "0.2.1" @@ -3609,16 +3715,6 @@ name = "utf8-ranges" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "util-error" -version = "0.1.0" -dependencies = [ - "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rlp 0.2.1", - "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "vec_map" version = "0.8.0" @@ -3649,7 +3745,8 @@ dependencies = [ "ethjson 0.1.0", "keccak-hash 0.1.2", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "patricia-trie 0.1.0", + "patricia-trie 0.2.0", + "patricia-trie-ethereum 0.1.0", "rlp 0.2.1", ] @@ -3667,21 +3764,21 @@ dependencies = [ "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "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.5 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-wasm 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pwasm-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "vm 0.1.0", - "wasmi 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmi 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmi" -version = "0.2.0" +version = "0.3.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)", + "parity-wasm 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3749,6 +3846,14 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "wincolor" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ws" version = "0.7.5" @@ -3832,7 +3937,7 @@ dependencies = [ "checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" "checksum bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1b7db437d718977f6dc9b2e3fd6fc343c02ac6b899b73fdd2179163447bd9ce9" -"checksum cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8b9d2900f78631a5876dc5d6c9033ede027253efcd33dd36b1309fc6cab97ee0" +"checksum cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "49ec142f5768efb5b7622aebc3fdbdbb8950a4b9ba996393cb76ef7466e8747d" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1cce36c92cb605414e9b824f866f5babe0a0368e39ea07393b9b63cf3844c0e6" "checksum cid 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d85ee025368e69063c420cbb2ed9f852cb03a5e69b73be021e65726ce03585b6" @@ -3852,12 +3957,14 @@ dependencies = [ "checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" "checksum daemonize 0.2.3 (git+https://github.com/paritytech/daemonize)" = "" "checksum difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3304d19798a8e067e48d8e69b2c37f0b5e9b4e462504ad9e27e9f3fce02bba8" +"checksum dirs 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "37a76dd8b997af7107d0bb69d43903cf37153a18266f8b3fdb9911f28efb5444" "checksum docopt 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d8acd393692c503b168471874953a2531df0e9ab77d0b6bbc582395743300a4a" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" "checksum edit-distance 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6a34f5204fbc13582de418611cf3a7dcdd07c6d312a5b631597ba72c06b9d9c9" "checksum either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740178ddf48b1a9e878e6d6509a1442a2d42fd2928aae8e7a6f8a36fb01981b3" "checksum elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "88d4851b005ef16de812ea9acdb7bece2f0a40dd86c07b85631d7dafa54537bb" "checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b" +"checksum env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0e6e40ebb0e66918a37b38c7acab4e10d299e0463fe2af5d29b9cc86710cfd2a" "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" "checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02" "checksum eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)" = "" @@ -3872,12 +3979,11 @@ dependencies = [ "checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" "checksum flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fac2277e84e5e858483756647a9d0aa8d9a2b7cba517fd84325a0aaa69a0909" "checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344" -"checksum fs-swap 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "31a94e9407e53addc49de767234a0b000978523c59117e5badb575ccbb8370f6" +"checksum fs-swap 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67f816b2a5f8a6628764a4323d1a8d9ad5303266c4e4e4486ba680f477ba7e62" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" -"checksum futures-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5cedfe9b6dc756220782cc1ba5bcb1fa091cdcba155e40d3556159c3db58043" "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" "checksum getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "65922871abd2f101a2eb0eaebadc66668e54a87ad9c3dd82520b5f86ede5eff9" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" @@ -3888,6 +3994,7 @@ dependencies = [ "checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa" "checksum hidapi 0.3.1 (git+https://github.com/paritytech/hidapi-rs)" = "" "checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07" +"checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" "checksum hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)" = "df4dd5dae401458087396b6db7fabc4d6760aa456a5fa8e92bda549f39cae661" "checksum hyper-rustls 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d6cdc1751771a14b8175764394f025e309a28c825ed9eaf97fa62bb831dc8c5" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" @@ -3912,11 +4019,13 @@ dependencies = [ "checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" "checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" "checksum libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "1e5d97d6708edaa407429faa671b942dc0f2727222fb6b6539bf1db936e4b121" +"checksum libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3ad660d7cb8c5822cd83d10897b0f1f1526792737a179e73896152f85b88c2" "checksum libusb 0.3.0 (git+https://github.com/paritytech/libusb-rs)" = "" "checksum libusb-sys 0.2.4 (git+https://github.com/paritytech/libusb-sys)" = "" "checksum linked-hash-map 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7860ec297f7008ff7a1e3382d7f7e1dcd69efc94751a2284bafc3d013c2aa939" "checksum linked-hash-map 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2aab0478615bb586559b0114d94dd8eca4fdbb73b443adcb0d00b61692b4bf" "checksum local-encoding 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1ceb20f39ff7ae42f3ff9795f3986b1daad821caaa1e1732a0944103a5a1a66" +"checksum lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "949826a5ccf18c1b3a7c3d57692778d21768b79e46eb9dd07bfc4c2160036c54" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" "checksum lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4d06ff7ff06f729ce5f4e227876cb88d10bc59cd4ae1e09fbb2bde15c850dc21" @@ -3955,9 +4064,9 @@ dependencies = [ "checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063" "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" "checksum parity-tokio-ipc 0.1.5 (git+https://github.com/nikvolf/parity-tokio-ipc)" = "" -"checksum parity-wasm 0.27.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a93ad771f67ce8a6af64c6444a99c07b15f4674203657496fc31244ffb1de2c3" +"checksum parity-wasm 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1c91199d14bd5b78ecade323d4a891d094799749c1b9e82d9c590c2e2849a40" "checksum parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d0dec124478845b142f68b446cbee953d14d4b41f1bc0425024417720dce693" -"checksum parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9fd9d732f2de194336fb02fe11f9eed13d9e76f13f4315b4d88a14ca411750cd" +"checksum parking_lot 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "901d6514273469bb17380c1ac3f51fb3ce54be1f960e51a6f04901eba313ab8d" "checksum parking_lot_core 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4f610cb9664da38e417ea3225f23051f589851999535290e077939838ab7a595" "checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356" "checksum petgraph 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "8b30dc85588cd02b9b76f5e386535db546d21dc68506cff2abebee0b6445e8e4" @@ -3975,7 +4084,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.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d51e9954a77aab7b4b606dc315a49cbed187924f163b6750cdf6d5677dbf0839" +"checksum pwasm-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "90d2b3c5bf24275fc77db6b14ec00a7a085d8ff9d1c4215fb6f6263e8d7b01bc" "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" @@ -3988,7 +4097,9 @@ dependencies = [ "checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "744554e01ccbd98fff8c457c3b092cd67af62a555a43bfe97ae8a0451f7799fa" +"checksum regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13c93d55961981ba9226a213b385216f83ab43bd6ac53ab16b2eeb47e337cf4e" "checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" +"checksum regex-syntax 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05b06a75f5217880fc5e905952a42750bf44787e56a6c6d6852ed0992f5e1d54" "checksum relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1576e382688d7e9deecea24417e350d3062d97e32e45d70b1cde65994ff1489a" "checksum ring 0.12.1 (git+https://github.com/paritytech/ring)" = "" "checksum rocksdb 0.4.5 (git+https://github.com/paritytech/rust-rocksdb)" = "" @@ -4038,6 +4149,7 @@ dependencies = [ "checksum tempfile 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "11ce2fe9db64b842314052e2421ac61a73ce41b898dc8e3750398b219c5fc1e0" "checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" "checksum term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e5b9a66db815dcfd2da92db471106457082577c3c278d4138ab3e3b4e189327" +"checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693" "checksum thread-id 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7fbf4c9d56b320106cd64fd024dadfa0be7cb4706725fc44a7d7ce952d820c1" @@ -4065,6 +4177,7 @@ dependencies = [ "checksum toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7540f4ffc193e0d3c94121edb19b055670d369f77d5804db11ae053a45b6e7e" "checksum transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "715254c8f0811be1a79ad3ea5e6fa3c8eddec2b03d7f5ba78cf093e56d79c24f" "checksum trezor-sys 1.0.0 (git+https://github.com/paritytech/trezor-sys)" = "" +"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" "checksum uint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "38051a96565903d81c9a9210ce11076b2218f3b352926baa1f5f6abbdfce8273" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284b6d3db520d67fbe88fd778c21510d1b0ba4a551e5d0fbb023d33405f6de8a" @@ -4083,7 +4196,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.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46df76793c28cd8f590d5667f540a81c1c245440a17b03560e381226e27cf348" +"checksum wasmi 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b4a6d379e9332b1b1f52c5a87f2481c85c7c931d8ec411963dfb8f26b1ec1e3" "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" @@ -4091,6 +4204,7 @@ dependencies = [ "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767" "checksum ws 0.7.5 (git+https://github.com/tomusdrw/ws-rs)" = "" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" "checksum xdg 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a66b7c2281ebde13cf4391d70d4c7e5946c3c25e72a7b859ca8f677dcd0b0c61" diff --git a/Cargo.toml b/Cargo.toml index 7424ba38bfa..04d0949bd2f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ number_prefix = "0.2" rpassword = "1.0" semver = "0.9" ansi_term = "0.10" -parking_lot = "0.5" +parking_lot = "0.6" regex = "0.2" atty = "0.2.8" toml = "0.4" @@ -32,7 +32,7 @@ futures-cpupool = "0.1" fdlimit = "0.1" ctrlc = { git = "https://github.com/paritytech/rust-ctrlc.git" } jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } -ethcore = { path = "ethcore" } +ethcore = { path = "ethcore", features = ["work-notify", "price-info", "stratum"] } ethcore-bytes = { path = "util/bytes" } ethcore-io = { path = "util/io" } ethcore-light = { path = "ethcore/light" } @@ -133,6 +133,8 @@ members = [ "transaction-pool", "whisper", "whisper/cli", + "util/keccak-hasher", + "util/patricia-trie-ethereum", ] [patch.crates-io] diff --git a/dapps/Cargo.toml b/dapps/Cargo.toml index f16233b607c..477ad9b067e 100644 --- a/dapps/Cargo.toml +++ b/dapps/Cargo.toml @@ -13,7 +13,7 @@ futures = "0.1" futures-cpupool = "0.1" linked-hash-map = "0.5" log = "0.3" -parking_lot = "0.5" +parking_lot = "0.6" mime_guess = "2.0.0-alpha.2" rand = "0.4" rustc-hex = "1.0" diff --git a/dapps/node-health/Cargo.toml b/dapps/node-health/Cargo.toml index c200a794117..0ac3f62ae4c 100644 --- a/dapps/node-health/Cargo.toml +++ b/dapps/node-health/Cargo.toml @@ -10,7 +10,7 @@ futures = "0.1" futures-cpupool = "0.1" log = "0.3" ntp = "0.5.0" -parking_lot = "0.5" +parking_lot = "0.6" serde = "1.0" serde_derive = "1.0" time = "0.1.35" diff --git a/docs/CHANGELOG-1.10.md b/docs/CHANGELOG-1.10.md index 71d6930b3de..caa440f6d77 100644 --- a/docs/CHANGELOG-1.10.md +++ b/docs/CHANGELOG-1.10.md @@ -1,3 +1,53 @@ +## Parity [v1.10.9](https://github.com/paritytech/parity/releases/tag/v1.10.9) (2018-07-07) + +Parity 1.10.9 is a bug-fix release to improve performance and stability. + +The full list of included changes: + +- Stable: 1.10.9 backports ([#9016](https://github.com/paritytech/parity/pull/9016)) + - Parity-version: bump stable to 1.10.9 + - Scripts: remove md5 checksums ([#8884](https://github.com/paritytech/parity/pull/8884)) + - Add support for --chain tobalaba ([#8870](https://github.com/paritytech/parity/pull/8870)) + - Add support for --chain tobalaba + - Only return error log for rustls ([#9025](https://github.com/paritytech/parity/pull/9025)) + - Fixes for misbehavior reporting in AuthorityRound ([#8998](https://github.com/paritytech/parity/pull/8998)) + - Aura: only report after checking for repeated skipped primaries + - Aura: refactor duplicate code for getting epoch validator set + - Aura: verify_external: report on validator set contract instance + - Aura: use correct validator set epoch number when reporting + - Aura: use epoch set when verifying blocks + - Aura: report skipped primaries when generating seal + - Aura: handle immediate transitions + - Aura: don't report skipped steps from genesis to first block + - Aura: fix reporting test + - Aura: refactor duplicate code to handle immediate_transitions + - Aura: let reporting fail on verify_block_basic + - Aura: add comment about possible failure of reporting + +## Parity [v1.10.8](https://github.com/paritytech/parity/releases/tag/v1.10.8) (2018-06-29) + +Parity 1.10.8 is a bug-fix release to improve performance and stability. + +The full list of included changes: + +- Backports ([#8986](https://github.com/paritytech/parity/pull/8986)) + - Snap: downgrade rust to revision 1.26.2, ref snapcraft/+bug/1778530 ([#8984](https://github.com/paritytech/parity/pull/8984)) + - Snap: downgrade rust to revision 1.26.2, ref snapcraft/+bug/1778530 + - Snap: use plugin rust + - Fix deadlock in blockchain. ([#8977](https://github.com/paritytech/parity/pull/8977)) + - Remove js-glue from workspace +- Bump stable to 1.10.8 ([#8951](https://github.com/paritytech/parity/pull/8951)) + - Parity-version: bump stable to 1.10.8 + - Update ropsten.json ([#8926](https://github.com/paritytech/parity/pull/8926)) + - Scripts: minor improvements ([#8930](https://github.com/paritytech/parity/pull/8930)) + - CI: enable 'latest' docker tag on master pipeline + - CI: mark both beta and stable as stable snap. + - CI: sign all windows binaries + - Scripts: remove whisper target not available in stable + - Scripts: fix gitlab strip binaries + - Scripts: fix docker build tag on latest using master ([#8952](https://github.com/paritytech/parity/pull/8952)) + - Rpc: cap gas limit of local calls ([#8943](https://github.com/paritytech/parity/pull/8943)) + ## Parity [v1.10.7](https://github.com/paritytech/parity/releases/tag/v1.10.7) (2018-06-20) Parity 1.10.7 is a bug-fix release to improve performance and stability. diff --git a/ethash/Cargo.toml b/ethash/Cargo.toml index 4bb1b50470e..61b3fa504f1 100644 --- a/ethash/Cargo.toml +++ b/ethash/Cargo.toml @@ -9,7 +9,7 @@ authors = ["Parity Technologies "] log = "0.3" keccak-hash = { path = "../util/hash" } primal = "0.2.3" -parking_lot = "0.5" +parking_lot = "0.6" crunchy = "0.1.0" memmap = "0.6" either = "1.0.0" diff --git a/ethash/src/cache.rs b/ethash/src/cache.rs index 21bd0e231ef..023e4bb468f 100644 --- a/ethash/src/cache.rs +++ b/ethash/src/cache.rs @@ -91,7 +91,7 @@ impl NodeCacheBuilder { pub fn new>>(optimize_for: T) -> Self { NodeCacheBuilder { - seedhash: Arc::new(Mutex::new(SeedHashCompute::new())), + seedhash: Arc::new(Mutex::new(SeedHashCompute::default())), optimize_for: optimize_for.into().unwrap_or_default(), } } diff --git a/ethash/src/seed_compute.rs b/ethash/src/seed_compute.rs index bc6f1d51e1b..7a3f89b9b5d 100644 --- a/ethash/src/seed_compute.rs +++ b/ethash/src/seed_compute.rs @@ -19,20 +19,13 @@ use keccak::{keccak_256, H256}; use std::cell::Cell; +#[derive(Default)] pub struct SeedHashCompute { prev_epoch: Cell, prev_seedhash: Cell, } impl SeedHashCompute { - #[inline] - pub fn new() -> SeedHashCompute { - SeedHashCompute { - prev_epoch: Cell::new(0), - prev_seedhash: Cell::new([0u8; 32]), - } - } - #[inline] fn reset_cache(&self) { self.prev_epoch.set(0); @@ -77,20 +70,20 @@ mod tests { #[test] fn test_seed_compute_once() { - let seed_compute = SeedHashCompute::new(); + let seed_compute = SeedHashCompute::default(); let hash = [241, 175, 44, 134, 39, 121, 245, 239, 228, 236, 43, 160, 195, 152, 46, 7, 199, 5, 253, 147, 241, 206, 98, 43, 3, 104, 17, 40, 192, 79, 106, 162]; assert_eq!(seed_compute.hash_block_number(486382), hash); } #[test] fn test_seed_compute_zero() { - let seed_compute = SeedHashCompute::new(); + let seed_compute = SeedHashCompute::default(); assert_eq!(seed_compute.hash_block_number(0), [0u8; 32]); } #[test] fn test_seed_compute_after_older() { - let seed_compute = SeedHashCompute::new(); + let seed_compute = SeedHashCompute::default(); // calculating an older value first shouldn't affect the result let _ = seed_compute.hash_block_number(50000); let hash = [241, 175, 44, 134, 39, 121, 245, 239, 228, 236, 43, 160, 195, 152, 46, 7, 199, 5, 253, 147, 241, 206, 98, 43, 3, 104, 17, 40, 192, 79, 106, 162]; @@ -99,7 +92,7 @@ mod tests { #[test] fn test_seed_compute_after_newer() { - let seed_compute = SeedHashCompute::new(); + let seed_compute = SeedHashCompute::default(); // calculating an newer value first shouldn't affect the result let _ = seed_compute.hash_block_number(972764); let hash = [241, 175, 44, 134, 39, 121, 245, 239, 228, 236, 43, 160, 195, 152, 46, 7, 199, 5, 253, 147, 241, 206, 98, 43, 3, 104, 17, 40, 192, 79, 106, 162]; diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 4d930926013..9c25cdccb15 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -16,16 +16,16 @@ crossbeam = "0.3" ethash = { path = "../ethash" } ethcore-bloom-journal = { path = "../util/bloom" } ethcore-bytes = { path = "../util/bytes" } -fetch = { path = "../util/fetch" } hashdb = { path = "../util/hashdb" } memorydb = { path = "../util/memorydb" } patricia-trie = { path = "../util/patricia_trie" } +patricia-trie-ethereum = { path = "../util/patricia-trie-ethereum" } ethcore-crypto = { path = "crypto" } error-chain = { version = "0.12", default-features = false } ethcore-io = { path = "../util/io" } ethcore-logger = { path = "../logger" } ethcore-miner = { path = "../miner" } -ethcore-stratum = { path = "./stratum" } +ethcore-stratum = { path = "./stratum", optional = true } ethcore-transaction = { path = "./transaction" } ethereum-types = "0.3" memory-cache = { path = "../util/memory_cache" } @@ -44,7 +44,7 @@ lru-cache = "0.1" num = { version = "0.1", default-features = false, features = ["bigint"] } num_cpus = "1.2" parity-machine = { path = "../machine" } -parking_lot = "0.5" +parking_lot = "0.6" rayon = "1.0" rand = "0.4" rlp = { path = "../util/rlp" } @@ -52,7 +52,6 @@ rlp_compress = { path = "../util/rlp_compress" } rlp_derive = { path = "../util/rlp_derive" } kvdb = { path = "../util/kvdb" } kvdb-memorydb = { path = "../util/kvdb-memorydb" } -util-error = { path = "../util/error" } snappy = { git = "https://github.com/paritytech/rust-snappy" } stop-guard = { path = "../util/stop-guard" } macros = { path = "../util/macros" } @@ -66,8 +65,9 @@ keccak-hash = { path = "../util/hash" } triehash = { path = "../util/triehash" } unexpected = { path = "../util/unexpected" } journaldb = { path = "../util/journaldb" } -tempdir = { version = "0.3", optional = true } +keccak-hasher = { path = "../util/keccak-hasher" } kvdb-rocksdb = { path = "../util/kvdb-rocksdb" } +tempdir = {version="0.3", optional = true} [target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))'.dependencies] hardware-wallet = { path = "../hw" } @@ -76,8 +76,8 @@ hardware-wallet = { path = "../hw" } fake-hardware-wallet = { path = "../util/fake-hardware-wallet" } [dev-dependencies] -trie-standardmap = { path = "../util/trie-standardmap" } tempdir = "0.3" +trie-standardmap = { path = "../util/trie-standardmap" } [features] # Display EVM debug traces. @@ -97,3 +97,6 @@ test-heavy = [] benches = [] # Compile test helpers test-helpers = ["tempdir"] +work-notify = ["ethcore-miner/work-notify"] +price-info = ["ethcore-miner/price-info"] +stratum = ["ethcore-stratum"] diff --git a/ethcore/evm/Cargo.toml b/ethcore/evm/Cargo.toml index fa7a99f9ded..654f7879a1c 100644 --- a/ethcore/evm/Cargo.toml +++ b/ethcore/evm/Cargo.toml @@ -11,7 +11,7 @@ lazy_static = "1.0" log = "0.3" vm = { path = "../vm" } keccak-hash = { path = "../../util/hash" } -parking_lot = "0.5" +parking_lot = "0.6" memory-cache = { path = "../../util/memory_cache" } [dev-dependencies] diff --git a/ethcore/light/Cargo.toml b/ethcore/light/Cargo.toml index ac3a70c3d82..3bdcd73b76e 100644 --- a/ethcore/light/Cargo.toml +++ b/ethcore/light/Cargo.toml @@ -14,6 +14,7 @@ ethcore-transaction = { path = "../transaction" } ethereum-types = "0.3" memorydb = { path = "../../util/memorydb" } patricia-trie = { path = "../../util/patricia_trie" } +patricia-trie-ethereum = { path = "../../util/patricia-trie-ethereum" } ethcore-network = { path = "../../util/network" } ethcore-io = { path = "../../util/io" } hashdb = { path = "../../util/hashdb" } @@ -29,9 +30,10 @@ itertools = "0.5" bincode = "0.8.0" serde = "1.0" serde_derive = "1.0" -parking_lot = "0.5" +parking_lot = "0.6" stats = { path = "../../util/stats" } keccak-hash = { path = "../../util/hash" } +keccak-hasher = { path = "../../util/keccak-hasher" } triehash = { path = "../../util/triehash" } kvdb = { path = "../../util/kvdb" } memory-cache = { path = "../../util/memory_cache" } diff --git a/ethcore/light/src/cht.rs b/ethcore/light/src/cht.rs index 805cca3cbc9..18b0e5b06c9 100644 --- a/ethcore/light/src/cht.rs +++ b/ethcore/light/src/cht.rs @@ -26,9 +26,11 @@ use ethcore::ids::BlockId; use ethereum_types::{H256, U256}; use hashdb::HashDB; +use keccak_hasher::KeccakHasher; use memorydb::MemoryDB; use bytes::Bytes; -use trie::{self, TrieMut, TrieDBMut, Trie, TrieDB, Recorder}; +use trie::{TrieMut, Trie, Recorder}; +use ethtrie::{self, TrieDB, TrieDBMut}; use rlp::{RlpStream, Rlp}; // encode a key. @@ -50,13 +52,13 @@ pub const SIZE: u64 = 2048; /// A canonical hash trie. This is generic over any database it can query. /// See module docs for more details. #[derive(Debug, Clone)] -pub struct CHT { +pub struct CHT> { db: DB, root: H256, // the root of this CHT. number: u64, } -impl CHT { +impl> CHT { /// Query the root of the CHT. pub fn root(&self) -> H256 { self.root } @@ -66,7 +68,7 @@ impl CHT { /// Generate an inclusion proof for the entry at a specific block. /// Nodes before level `from_level` will be omitted. /// Returns an error on an incomplete trie, and `Ok(None)` on an unprovable request. - pub fn prove(&self, num: u64, from_level: u32) -> trie::Result>> { + pub fn prove(&self, num: u64, from_level: u32) -> ethtrie::Result>> { if block_to_cht_number(num) != Some(self.number) { return Ok(None) } let mut recorder = Recorder::with_depth(from_level); @@ -90,10 +92,10 @@ pub struct BlockInfo { /// Build an in-memory CHT from a closure which provides necessary information /// about blocks. If the fetcher ever fails to provide the info, the CHT /// will not be generated. -pub fn build(cht_num: u64, mut fetcher: F) -> Option> +pub fn build(cht_num: u64, mut fetcher: F) -> Option>> where F: FnMut(BlockId) -> Option { - let mut db = MemoryDB::new(); + let mut db = MemoryDB::::new(); // start from the last block by number and work backwards. let last_num = start_number(cht_num + 1) - 1; @@ -147,7 +149,7 @@ pub fn compute_root(cht_num: u64, iterable: I) -> Option /// verify the given trie branch and extract the canonical hash and total difficulty. // TODO: better support for partially-checked queries. pub fn check_proof(proof: &[Bytes], num: u64, root: H256) -> Option<(H256, U256)> { - let mut db = MemoryDB::new(); + let mut db = MemoryDB::::new(); for node in proof { db.insert(&node[..]); } let res = match TrieDB::new(&db, &root) { diff --git a/ethcore/light/src/client/header_chain.rs b/ethcore/light/src/client/header_chain.rs index 44fb311b682..957a1ea4330 100644 --- a/ethcore/light/src/client/header_chain.rs +++ b/ethcore/light/src/client/header_chain.rs @@ -28,28 +28,21 @@ use std::collections::BTreeMap; use std::sync::Arc; +use cache::Cache; use cht; - use ethcore::block_status::BlockStatus; -use ethcore::error::{Error, BlockImportError, BlockImportErrorKind, BlockError}; use ethcore::encoded; +use ethcore::engines::epoch::{Transition as EpochTransition, PendingTransition as PendingEpochTransition}; +use ethcore::error::{Error, BlockImportError, BlockImportErrorKind, BlockError}; use ethcore::header::Header; use ethcore::ids::BlockId; use ethcore::spec::{Spec, SpecHardcodedSync}; -use ethcore::engines::epoch::{ - Transition as EpochTransition, - PendingTransition as PendingEpochTransition -}; - -use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp}; -use heapsize::HeapSizeOf; use ethereum_types::{H256, H264, U256}; -use plain_hasher::H256FastMap; +use heapsize::HeapSizeOf; use kvdb::{DBTransaction, KeyValueDB}; - -use cache::Cache; use parking_lot::{Mutex, RwLock}; - +use plain_hasher::H256FastMap; +use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp}; use smallvec::SmallVec; /// Store at least this many candidate headers at all times. diff --git a/ethcore/light/src/lib.rs b/ethcore/light/src/lib.rs index d7469fdcee0..2000131a696 100644 --- a/ethcore/light/src/lib.rs +++ b/ethcore/light/src/lib.rs @@ -64,8 +64,10 @@ extern crate hashdb; extern crate heapsize; extern crate futures; extern crate itertools; +extern crate keccak_hasher; extern crate memorydb; extern crate patricia_trie as trie; +extern crate patricia_trie_ethereum as ethtrie; extern crate plain_hasher; extern crate rand; extern crate rlp; diff --git a/ethcore/light/src/net/mod.rs b/ethcore/light/src/net/mod.rs index 179f7090036..27d240feda9 100644 --- a/ethcore/light/src/net/mod.rs +++ b/ethcore/light/src/net/mod.rs @@ -20,22 +20,20 @@ use transaction::UnverifiedTransaction; -use io::TimerToken; -use network::{NetworkProtocolHandler, NetworkContext, PeerId}; -use rlp::{RlpStream, Rlp}; use ethereum_types::{H256, U256}; +use io::TimerToken; use kvdb::DBValue; +use network::{NetworkProtocolHandler, NetworkContext, PeerId}; use parking_lot::{Mutex, RwLock}; -use std::time::{Duration, Instant}; - +use provider::Provider; +use request::{Request, NetworkRequests as Requests, Response}; +use rlp::{RlpStream, Rlp}; use std::collections::{HashMap, HashSet}; use std::fmt; +use std::ops::{BitOr, BitAnd, Not}; use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; -use std::ops::{BitOr, BitAnd, Not}; - -use provider::Provider; -use request::{Request, NetworkRequests as Requests, Response}; +use std::time::{Duration, Instant}; use self::request_credits::{Credits, FlowParams}; use self::context::{Ctx, TickCtx}; diff --git a/ethcore/light/src/net/status.rs b/ethcore/light/src/net/status.rs index d89db173cb8..98b29f3e360 100644 --- a/ethcore/light/src/net/status.rs +++ b/ethcore/light/src/net/status.rs @@ -16,8 +16,8 @@ //! Peer status and capabilities. -use rlp::{DecoderError, Encodable, Decodable, RlpStream, Rlp}; use ethereum_types::{H256, U256}; +use rlp::{DecoderError, Encodable, Decodable, RlpStream, Rlp}; use super::request_credits::FlowParams; diff --git a/ethcore/light/src/net/tests/mod.rs b/ethcore/light/src/net/tests/mod.rs index e182f38b8a6..0c9971d75bd 100644 --- a/ethcore/light/src/net/tests/mod.rs +++ b/ethcore/light/src/net/tests/mod.rs @@ -19,20 +19,18 @@ use ethcore::blockchain_info::BlockChainInfo; use ethcore::client::{EachBlockWith, TestBlockChainClient}; -use ethcore::ids::BlockId; use ethcore::encoded; -use network::{PeerId, NodeId}; -use transaction::{Action, PendingTransaction}; - +use ethcore::ids::BlockId; +use ethereum_types::{H256, U256, Address}; +use net::{LightProtocol, Params, packet, Peer}; use net::context::IoContext; use net::status::{Capabilities, Status}; -use net::{LightProtocol, Params, packet, Peer}; +use network::{PeerId, NodeId}; use provider::Provider; use request; use request::*; - use rlp::{Rlp, RlpStream}; -use ethereum_types::{H256, U256, Address}; +use transaction::{Action, PendingTransaction}; use std::sync::Arc; use std::time::Instant; diff --git a/ethcore/light/src/on_demand/request.rs b/ethcore/light/src/on_demand/request.rs index 4cac6b629db..9feb0a670ff 100644 --- a/ethcore/light/src/on_demand/request.rs +++ b/ethcore/light/src/on_demand/request.rs @@ -18,26 +18,25 @@ use std::sync::Arc; +use bytes::Bytes; use ethcore::basic_account::BasicAccount; use ethcore::encoded; use ethcore::engines::{EthEngine, StateDependentProof}; use ethcore::machine::EthereumMachine; use ethcore::receipt::Receipt; use ethcore::state::{self, ProvedExecution}; -use transaction::SignedTransaction; -use vm::EnvInfo; -use hash::{KECCAK_NULL_RLP, KECCAK_EMPTY, KECCAK_EMPTY_LIST_RLP, keccak}; - -use request::{self as net_request, IncompleteRequest, CompleteRequest, Output, OutputKind, Field}; - -use rlp::{RlpStream, Rlp}; use ethereum_types::{H256, U256, Address}; -use parking_lot::Mutex; +use ethtrie::{TrieError, TrieDB}; +use hash::{KECCAK_NULL_RLP, KECCAK_EMPTY, KECCAK_EMPTY_LIST_RLP, keccak}; use hashdb::HashDB; use kvdb::DBValue; -use bytes::Bytes; use memorydb::MemoryDB; -use trie::{Trie, TrieDB, TrieError}; +use parking_lot::Mutex; +use request::{self as net_request, IncompleteRequest, CompleteRequest, Output, OutputKind, Field}; +use rlp::{RlpStream, Rlp}; +use transaction::SignedTransaction; +use trie::Trie; +use vm::EnvInfo; const SUPPLIED_MATCHES: &'static str = "supplied responses always match produced requests; enforced by `check_response`; qed"; @@ -935,11 +934,12 @@ mod tests { use ethereum_types::{H256, Address}; use memorydb::MemoryDB; use parking_lot::Mutex; - use trie::{Trie, TrieMut, SecTrieDB, SecTrieDBMut}; - use trie::recorder::Recorder; + use trie::{Trie, TrieMut}; + use ethtrie::{SecTrieDB, SecTrieDBMut}; + use trie::Recorder; use hash::keccak; - use ethcore::client::{BlockChainClient, BlockInfo, TestBlockChainClient, EachBlockWith}; + use ::ethcore::client::{BlockChainClient, BlockInfo, TestBlockChainClient, EachBlockWith}; use ethcore::header::Header; use ethcore::encoded; use ethcore::receipt::{Receipt, TransactionOutcome}; diff --git a/ethcore/node_filter/Cargo.toml b/ethcore/node_filter/Cargo.toml index 11be807652b..597f9a9620a 100644 --- a/ethcore/node_filter/Cargo.toml +++ b/ethcore/node_filter/Cargo.toml @@ -12,7 +12,7 @@ ethcore-network = { path = "../../util/network" } ethcore-network-devp2p = { path = "../../util/network-devp2p" } ethereum-types = "0.3" log = "0.3" -parking_lot = "0.5" +parking_lot = "0.6" ethabi = "5.1" ethabi-derive = "5.0" ethabi-contract = "5.0" diff --git a/ethcore/private-tx/Cargo.toml b/ethcore/private-tx/Cargo.toml index e32c81bc26f..42bcc4f2026 100644 --- a/ethcore/private-tx/Cargo.toml +++ b/ethcore/private-tx/Cargo.toml @@ -24,8 +24,9 @@ fetch = { path = "../../util/fetch" } futures = "0.1" keccak-hash = { path = "../../util/hash" } log = "0.3" -parking_lot = "0.5" +parking_lot = "0.6" patricia-trie = { path = "../../util/patricia_trie" } +patricia-trie-ethereum = { path = "../../util/patricia-trie-ethereum" } rand = "0.3" rlp = { path = "../../util/rlp" } rlp_derive = { path = "../../util/rlp_derive" } diff --git a/ethcore/private-tx/src/error.rs b/ethcore/private-tx/src/error.rs index 0456b330530..55a75d6d9ed 100644 --- a/ethcore/private-tx/src/error.rs +++ b/ethcore/private-tx/src/error.rs @@ -16,7 +16,7 @@ use ethereum_types::Address; use rlp::DecoderError; -use trie::TrieError; +use ethtrie::TrieError; use ethcore::account_provider::SignError; use ethcore::error::{Error as EthcoreError, ExecutionError}; use transaction::Error as TransactionError; diff --git a/ethcore/private-tx/src/lib.rs b/ethcore/private-tx/src/lib.rs index 38285ed85b5..2034ea7fa7c 100644 --- a/ethcore/private-tx/src/lib.rs +++ b/ethcore/private-tx/src/lib.rs @@ -40,6 +40,7 @@ extern crate futures; extern crate keccak_hash as hash; extern crate parking_lot; extern crate patricia_trie as trie; +extern crate patricia_trie_ethereum as ethtrie; extern crate rlp; extern crate url; extern crate rustc_hex; @@ -82,7 +83,7 @@ use ethcore::client::{ Client, ChainNotify, ChainRoute, ChainMessageType, ClientIoMessage, BlockId, CallContract }; use ethcore::account_provider::AccountProvider; -use ethcore::miner::{self, Miner, MinerService}; +use ethcore::miner::{self, Miner, MinerService, pool_client::NonceCache}; use ethcore::trace::{Tracer, VMTracer}; use rustc_hex::FromHex; use ethkey::Password; @@ -95,6 +96,9 @@ use_contract!(private, "PrivateContract", "res/private.json"); /// Initialization vector length. const INIT_VEC_LEN: usize = 16; +/// Size of nonce cache +const NONCE_CACHE_SIZE: usize = 128; + /// Configurtion for private transaction provider #[derive(Default, PartialEq, Debug, Clone)] pub struct ProviderConfig { @@ -244,7 +248,7 @@ impl Provider where { Ok(original_transaction) } - fn pool_client<'a>(&'a self, nonce_cache: &'a RwLock>) -> miner::pool_client::PoolClient<'a, Client> { + fn pool_client<'a>(&'a self, nonce_cache: &'a NonceCache) -> miner::pool_client::PoolClient<'a, Client> { let engine = self.client.engine(); let refuse_service_transactions = true; miner::pool_client::PoolClient::new( @@ -263,7 +267,7 @@ impl Provider where { /// can be replaced with a single `drain()` method instead. /// Thanks to this we also don't really need to lock the entire verification for the time of execution. fn process_queue(&self) -> Result<(), Error> { - let nonce_cache = Default::default(); + let nonce_cache = NonceCache::new(NONCE_CACHE_SIZE); let mut verification_queue = self.transactions_for_verification.lock(); let ready_transactions = verification_queue.ready_transactions(self.pool_client(&nonce_cache)); for transaction in ready_transactions { @@ -584,7 +588,7 @@ impl Importer for Arc { trace!("Validating transaction: {:?}", original_tx); // Verify with the first account available trace!("The following account will be used for verification: {:?}", validation_account); - let nonce_cache = Default::default(); + let nonce_cache = NonceCache::new(NONCE_CACHE_SIZE); self.transactions_for_verification.lock().add_transaction( original_tx, contract, diff --git a/ethcore/res/ethereum/social.json b/ethcore/res/ethereum/social.json index 52b442d0886..2ad8fec8b06 100644 --- a/ethcore/res/ethereum/social.json +++ b/ethcore/res/ethereum/social.json @@ -45,12 +45,11 @@ "gasLimit": "0x1388" }, "nodes": [ - "enode://54d0824a268747046b6cabc7ee3afda48edba319f0d175e9e505aa9d425a1872b8b6f9ebf8f3b0a10dc7611a4c44ddec0fc691e5a5cde23e06fc4e4b3ff9dbef@13.125.185.147:30303", - "enode://7e150d47637177f675e20d663fc2500987f2149332caf23da522d92363be8a7880ef9150a6183e9031288a441e0457239474967a111eafce17e19a4288076ea9@18.219.40.235:30303", - "enode://6244c9d9cd288015d7ff165e90f3bb5649e34467e095a47c6d3c56e8fb8c849b3b4db683ff3c7ae8a654bbdc07ef12ee2fd7d72831ac213723281c1b0cc90599@13.250.220.98:30303", - "enode://e39f162b9f4b6ed6f098550f7867c2fb068fc66f362b3db0f45124c43ea18508f5ceef4e0e4de53d301e14a6f1683226aeb931d7401b4e83b5a583153ffdd7fd@52.57.98.157:30303", - "enode://54b4a117d66dc3aa93358dec1b31d4f38e72e4381b3e28a65ac6f1aaac3b304ebbe41d32cc864fa69a9a6815c34cf9b8965690dc174a5f72af14547b601b7924@222.239.255.71:30303", - "enode://851f14c5cc86cbc0a81acfcbe5dd99ad5c823435357219df736932c5f89ad4318f6973a553857a32d97a71793f5a35c062d46320be282aa0a80b06b9c6b624e4@13.125.232.71:30303" + "enode://38a3bdd683008f2b404fbd8e59a4ae7377fb1b796be8aca02861a6864304df7f443ae9669d0072d567eb30ab2183556a3cd832b8f2c99246e9a3d9f64ecdc1af@52.78.243.91:30303", + "enode://ee31120190438ca3842afccca9d732d8bfca4bbf9b846fd2bb11178194aa49a74d77ff4801d50a7bd9eb3629f8903661d0fb973e7f43b395263530b390002033@13.209.99.197:30303", + "enode://d538165bf6026602ba9ac296b2b56994e03bb917c73b79cbb11df75a45576fa74df494097bdbcda9bf2c0954a47a65b65674780fa1fbde5bcc89a34870d44983@13.125.206.82:30303", + "enode://67b5de9a4562ba0a01877e3876249c8e551844424773bdbf9713d126b3f144ac7a49d8eb06fc9830871f03b50a7d9b5d98d9d1be5544aef8afcaa10eea2fb9eb@13.125.68.29:30303", + "enode://2d31dd1f8acd956cf36a1c3f27e374f5b94c55df4206749b03a6d0a50366c8090280c91f71aad00886cbde6ebbfcabeaaa91bd910b16e4fb398b337e9ecfdbd9@13.125.232.71:30303" ], "accounts": { "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, diff --git a/ethcore/res/wasm-tests b/ethcore/res/wasm-tests index fb111c82def..474110de59a 160000 --- a/ethcore/res/wasm-tests +++ b/ethcore/res/wasm-tests @@ -1 +1 @@ -Subproject commit fb111c82deff8759f54a5038d07cecc77cb5a663 +Subproject commit 474110de59a0f632b20615256c913b144c49354c diff --git a/ethcore/src/account_db.rs b/ethcore/src/account_db.rs index 8fc4b95c6ee..dd05d22cbc6 100644 --- a/ethcore/src/account_db.rs +++ b/ethcore/src/account_db.rs @@ -15,12 +15,13 @@ // along with Parity. If not, see . //! DB backend wrapper for Account trie -use std::collections::HashMap; -use hash::{KECCAK_NULL_RLP, keccak}; use ethereum_types::H256; +use hash::{KECCAK_NULL_RLP, keccak}; +use hashdb::{HashDB, AsHashDB}; +use keccak_hasher::KeccakHasher; use kvdb::DBValue; -use hashdb::HashDB; use rlp::NULL_RLP; +use std::collections::HashMap; #[cfg(test)] use ethereum_types::Address; @@ -44,7 +45,7 @@ fn combine_key<'a>(address_hash: &'a H256, key: &'a H256) -> H256 { /// A factory for different kinds of account dbs. #[derive(Debug, Clone)] pub enum Factory { - /// Mangle hashes based on address. + /// Mangle hashes based on address. This is the default. Mangled, /// Don't mangle hashes. Plain, @@ -57,7 +58,7 @@ impl Default for Factory { impl Factory { /// Create a read-only accountdb. /// This will panic when write operations are called. - pub fn readonly<'db>(&self, db: &'db HashDB, address_hash: H256) -> Box { + pub fn readonly<'db>(&self, db: &'db HashDB, address_hash: H256) -> Box + 'db> { match *self { Factory::Mangled => Box::new(AccountDB::from_hash(db, address_hash)), Factory::Plain => Box::new(Wrapping(db)), @@ -65,7 +66,7 @@ impl Factory { } /// Create a new mutable hashdb. - pub fn create<'db>(&self, db: &'db mut HashDB, address_hash: H256) -> Box { + pub fn create<'db>(&self, db: &'db mut HashDB, address_hash: H256) -> Box + 'db> { match *self { Factory::Mangled => Box::new(AccountDBMut::from_hash(db, address_hash)), Factory::Plain => Box::new(WrappingMut(db)), @@ -77,19 +78,19 @@ impl Factory { /// DB backend wrapper for Account trie /// Transforms trie node keys for the database pub struct AccountDB<'db> { - db: &'db HashDB, + db: &'db HashDB, address_hash: H256, } impl<'db> AccountDB<'db> { /// Create a new AccountDB from an address. #[cfg(test)] - pub fn new(db: &'db HashDB, address: &Address) -> Self { + pub fn new(db: &'db HashDB, address: &Address) -> Self { Self::from_hash(db, keccak(address)) } /// Create a new AcountDB from an address' hash. - pub fn from_hash(db: &'db HashDB, address_hash: H256) -> Self { + pub fn from_hash(db: &'db HashDB, address_hash: H256) -> Self { AccountDB { db: db, address_hash: address_hash, @@ -97,7 +98,12 @@ impl<'db> AccountDB<'db> { } } -impl<'db> HashDB for AccountDB<'db>{ +impl<'db> AsHashDB for AccountDB<'db> { + fn as_hashdb(&self) -> &HashDB { self } + fn as_hashdb_mut(&mut self) -> &mut HashDB { self } +} + +impl<'db> HashDB for AccountDB<'db> { fn keys(&self) -> HashMap { unimplemented!() } @@ -131,19 +137,19 @@ impl<'db> HashDB for AccountDB<'db>{ /// DB backend wrapper for Account trie pub struct AccountDBMut<'db> { - db: &'db mut HashDB, + db: &'db mut HashDB, address_hash: H256, } impl<'db> AccountDBMut<'db> { /// Create a new AccountDB from an address. #[cfg(test)] - pub fn new(db: &'db mut HashDB, address: &Address) -> Self { + pub fn new(db: &'db mut HashDB, address: &Address) -> Self { Self::from_hash(db, keccak(address)) } /// Create a new AcountDB from an address' hash. - pub fn from_hash(db: &'db mut HashDB, address_hash: H256) -> Self { + pub fn from_hash(db: &'db mut HashDB, address_hash: H256) -> Self { AccountDBMut { db: db, address_hash: address_hash, @@ -156,7 +162,7 @@ impl<'db> AccountDBMut<'db> { } } -impl<'db> HashDB for AccountDBMut<'db>{ +impl<'db> HashDB for AccountDBMut<'db>{ fn keys(&self) -> HashMap { unimplemented!() } @@ -202,9 +208,19 @@ impl<'db> HashDB for AccountDBMut<'db>{ } } -struct Wrapping<'db>(&'db HashDB); +impl<'db> AsHashDB for AccountDBMut<'db> { + fn as_hashdb(&self) -> &HashDB { self } + fn as_hashdb_mut(&mut self) -> &mut HashDB { self } +} + +struct Wrapping<'db>(&'db HashDB); -impl<'db> HashDB for Wrapping<'db> { +impl<'db> AsHashDB for Wrapping<'db> { + fn as_hashdb(&self) -> &HashDB { self } + fn as_hashdb_mut(&mut self) -> &mut HashDB { self } +} + +impl<'db> HashDB for Wrapping<'db> { fn keys(&self) -> HashMap { unimplemented!() } @@ -236,9 +252,13 @@ impl<'db> HashDB for Wrapping<'db> { } } -struct WrappingMut<'db>(&'db mut HashDB); +struct WrappingMut<'db>(&'db mut HashDB); +impl<'db> AsHashDB for WrappingMut<'db> { + fn as_hashdb(&self) -> &HashDB { self } + fn as_hashdb_mut(&mut self) -> &mut HashDB { self } +} -impl<'db> HashDB for WrappingMut<'db>{ +impl<'db> HashDB for WrappingMut<'db>{ fn keys(&self) -> HashMap { unimplemented!() } diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 91de4d379ca..ba21cb41761 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -17,28 +17,27 @@ //! Blockchain block. use std::cmp; -use std::sync::Arc; use std::collections::HashSet; -use hash::{keccak, KECCAK_NULL_RLP, KECCAK_EMPTY_LIST_RLP}; -use triehash::ordered_trie_root; +use std::sync::Arc; -use rlp::{Rlp, RlpStream, Encodable, Decodable, DecoderError, encode_list}; -use ethereum_types::{H256, U256, Address, Bloom}; use bytes::Bytes; -use unexpected::{Mismatch, OutOfBounds}; - -use vm::{EnvInfo, LastHashes}; use engines::EthEngine; use error::{Error, BlockError}; +use ethereum_types::{H256, U256, Address, Bloom}; use factory::Factories; +use hash::{keccak, KECCAK_NULL_RLP, KECCAK_EMPTY_LIST_RLP}; use header::{Header, ExtendedHeader}; use receipt::{Receipt, TransactionOutcome}; -use state::State; +use rlp::{Rlp, RlpStream, Encodable, Decodable, DecoderError, encode_list}; use state_db::StateDB; +use state::State; use trace::Tracing; use transaction::{UnverifiedTransaction, SignedTransaction, Error as TransactionError}; +use triehash::ordered_trie_root; +use unexpected::{Mismatch, OutOfBounds}; use verification::PreverifiedBlock; use views::BlockView; +use vm::{EnvInfo, LastHashes}; /// A block, encoded as it is on the block chain. #[derive(Default, Debug, Clone, PartialEq)] diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 58a5a06b0da..b2ba886b4dd 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -17,37 +17,38 @@ //! Blockchain database. use std::collections::{HashMap, HashSet}; +use std::{mem, io}; use std::path::Path; use std::sync::Arc; -use std::{mem, io}; -use itertools::Itertools; -use blooms_db; -use heapsize::HeapSizeOf; -use ethereum_types::{H256, Bloom, BloomRef, U256}; -use parking_lot::{Mutex, RwLock}; -use bytes::Bytes; -use rlp::RlpStream; -use rlp_compress::{compress, decompress, blocks_swapper}; -use header::*; -use transaction::*; -use views::{BlockView, HeaderView}; -use log_entry::{LogEntry, LocalizedLogEntry}; -use receipt::Receipt; + +use ansi_term::Colour; +use blockchain::{CacheSize, ImportRoute, Config}; use blockchain::best_block::{BestBlock, BestAncientBlock}; use blockchain::block_info::{BlockInfo, BlockLocation, BranchBecomingCanonChainData}; use blockchain::extras::{BlockReceipts, BlockDetails, TransactionAddress, EPOCH_KEY_PREFIX, EpochTransitions}; -use types::blockchain_info::BlockChainInfo; -use types::tree_route::TreeRoute; use blockchain::update::{ExtrasUpdate, ExtrasInsert}; -use blockchain::{CacheSize, ImportRoute, Config}; -use db::{self, Writable, Readable, CacheUpdatePolicy}; +use blooms_db; +use bytes::Bytes; use cache_manager::CacheManager; +use db::{self, Writable, Readable, CacheUpdatePolicy}; use encoded; -use engines::ForkChoice; use engines::epoch::{Transition as EpochTransition, PendingTransition as PendingEpochTransition}; -use rayon::prelude::*; -use ansi_term::Colour; +use engines::ForkChoice; +use ethereum_types::{H256, Bloom, BloomRef, U256}; +use header::*; +use heapsize::HeapSizeOf; +use itertools::Itertools; use kvdb::{DBTransaction, KeyValueDB}; +use log_entry::{LogEntry, LocalizedLogEntry}; +use parking_lot::{Mutex, RwLock}; +use rayon::prelude::*; +use receipt::Receipt; +use rlp_compress::{compress, decompress, blocks_swapper}; +use rlp::RlpStream; +use transaction::*; +use types::blockchain_info::BlockChainInfo; +use types::tree_route::TreeRoute; +use views::{BlockView, HeaderView}; /// Database backing `BlockChain`. pub trait BlockChainDB: Send + Sync { diff --git a/ethcore/src/blockchain/extras.rs b/ethcore/src/blockchain/extras.rs index 6b54fee2e11..bbf67374a1b 100644 --- a/ethcore/src/blockchain/extras.rs +++ b/ethcore/src/blockchain/extras.rs @@ -16,17 +16,17 @@ //! Blockchain DB extras. -use std::ops; use std::io::Write; +use std::ops; + use db::Key; use engines::epoch::{Transition as EpochTransition}; +use ethereum_types::{H256, H264, U256}; use header::BlockNumber; -use receipt::Receipt; -use rlp; - use heapsize::HeapSizeOf; -use ethereum_types::{H256, H264, U256}; use kvdb::PREFIX_LEN as DB_PREFIX_LEN; +use receipt::Receipt; +use rlp; /// Represents index of extra data in database #[derive(Copy, Debug, Hash, Eq, PartialEq, Clone)] @@ -252,6 +252,7 @@ pub struct EpochTransitions { #[cfg(test)] mod tests { use rlp::*; + use super::BlockReceipts; #[test] diff --git a/ethcore/src/cache_manager.rs b/ethcore/src/cache_manager.rs index 4199cb1d593..07a9750a0ee 100644 --- a/ethcore/src/cache_manager.rs +++ b/ethcore/src/cache_manager.rs @@ -19,7 +19,7 @@ use std::hash::Hash; const COLLECTION_QUEUE_SIZE: usize = 8; -pub struct CacheManager where T: Eq + Hash { +pub struct CacheManager { pref_cache_size: usize, max_cache_size: usize, bytes_per_cache_entry: usize, diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 37dd71b9b4a..bdd00a27379 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -28,7 +28,6 @@ use itertools::Itertools; use journaldb; use trie::{TrieSpec, TrieFactory, Trie}; use kvdb::{DBValue, KeyValueDB, DBTransaction}; -use util_error::UtilError; // other use ethereum_types::{H256, Address, U256}; @@ -87,7 +86,6 @@ pub use verification::queue::QueueInfo as BlockQueueInfo; use_contract!(registry, "Registry", "res/contracts/registrar.json"); -const MAX_TX_QUEUE_SIZE: usize = 4096; const MAX_ANCIENT_BLOCKS_QUEUE_SIZE: usize = 4096; // Max number of blocks imported at once. const MAX_ANCIENT_BLOCKS_TO_IMPORT: usize = 4; @@ -443,7 +441,7 @@ impl Importer { { trace_time!("import_old_block"); // verify the block, passing the chain for updating the epoch verifier. - let mut rng = OsRng::new().map_err(UtilError::from)?; + let mut rng = OsRng::new()?; self.ancient_verifier.verify(&mut rng, &header, &chain)?; // Commit results @@ -760,13 +758,12 @@ impl Client { tracedb: tracedb, engine: engine, pruning: config.pruning.clone(), - config: config, db: RwLock::new(db.clone()), state_db: RwLock::new(state_db), report: RwLock::new(Default::default()), io_channel: Mutex::new(message_channel), notify: RwLock::new(Vec::new()), - queue_transactions: IoChannelQueue::new(MAX_TX_QUEUE_SIZE), + queue_transactions: IoChannelQueue::new(config.transaction_verification_queue_size), queue_ancient_blocks: IoChannelQueue::new(MAX_ANCIENT_BLOCKS_QUEUE_SIZE), queued_ancient_blocks: Default::default(), ancient_blocks_import_lock: Default::default(), @@ -779,6 +776,7 @@ impl Client { registrar_address, exit_handler: Mutex::new(None), importer, + config, }); // prune old states. @@ -1713,7 +1711,7 @@ impl BlockChainClient for Client { fn list_storage(&self, id: BlockId, account: &Address, after: Option<&H256>, count: u64) -> Option> { if !self.factories.trie.is_fat() { - trace!(target: "fatdb", "list_stroage: Not a fat DB"); + trace!(target: "fatdb", "list_storage: Not a fat DB"); return None; } diff --git a/ethcore/src/client/config.rs b/ethcore/src/client/config.rs index afc8e168684..a7929ddc98c 100644 --- a/ethcore/src/client/config.rs +++ b/ethcore/src/client/config.rs @@ -70,12 +70,6 @@ pub enum Mode { Off, } -impl Default for Mode { - fn default() -> Self { - Mode::Active - } -} - impl Display for Mode { fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { match *self { @@ -88,7 +82,7 @@ impl Display for Mode { } /// Client configuration. Includes configs for all sub-systems. -#[derive(Debug, PartialEq, Default, Clone)] +#[derive(Debug, PartialEq, Clone)] pub struct ClientConfig { /// Block queue configuration. pub queue: QueueConfig, @@ -124,11 +118,39 @@ pub struct ClientConfig { pub history_mem: usize, /// Check seal valididity on block import pub check_seal: bool, + /// Maximal number of transactions queued for verification in a separate thread. + pub transaction_verification_queue_size: usize, } +impl Default for ClientConfig { + fn default() -> Self { + let mb = 1024 * 1024; + ClientConfig { + queue: Default::default(), + blockchain: Default::default(), + tracing: Default::default(), + vm_type: Default::default(), + fat_db: false, + pruning: journaldb::Algorithm::OverlayRecent, + name: "default".into(), + db_cache_size: None, + db_compaction: Default::default(), + db_wal: true, + mode: Mode::Active, + spec_name: "".into(), + verifier_type: VerifierType::Canon, + state_cache_size: 1 * mb, + jump_table_size: 1 * mb, + history: 64, + history_mem: 32 * mb, + check_seal: true, + transaction_verification_queue_size: 8192, + } + } +} #[cfg(test)] mod test { - use super::{DatabaseCompactionProfile, Mode}; + use super::DatabaseCompactionProfile; #[test] fn test_default_compaction_profile() { @@ -141,9 +163,4 @@ mod test { assert_eq!(DatabaseCompactionProfile::SSD, "ssd".parse().unwrap()); assert_eq!(DatabaseCompactionProfile::HDD, "hdd".parse().unwrap()); } - - #[test] - fn test_mode_default() { - assert_eq!(Mode::default(), Mode::Active); - } } diff --git a/ethcore/src/client/error.rs b/ethcore/src/client/error.rs index 803499b9c9a..6851a4057b0 100644 --- a/ethcore/src/client/error.rs +++ b/ethcore/src/client/error.rs @@ -15,16 +15,16 @@ // along with Parity. If not, see . use std::fmt::{Display, Formatter, Error as FmtError}; -use util_error::UtilError; -use trie::TrieError; +use std::io; +use ethtrie::TrieError; /// Client configuration errors. #[derive(Debug)] pub enum Error { /// TrieDB-related error. Trie(TrieError), - /// Util error - Util(UtilError), + /// Io error. + Io(io::Error), } impl From for Error { @@ -33,9 +33,9 @@ impl From for Error { } } -impl From for Error { - fn from(err: UtilError) -> Self { - Error::Util(err) +impl From for Error { + fn from(err: io::Error) -> Self { + Error::Io(err) } } @@ -49,7 +49,7 @@ impl Display for Error { fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { match *self { Error::Trie(ref err) => write!(f, "{}", err), - Error::Util(ref err) => write!(f, "{}", err), + Error::Io(ref err) => write!(f, "{}", err), } } } diff --git a/ethcore/src/client/evm_test_client.rs b/ethcore/src/client/evm_test_client.rs index eccb9971a81..f11cae3b0d4 100644 --- a/ethcore/src/client/evm_test_client.rs +++ b/ethcore/src/client/evm_test_client.rs @@ -25,12 +25,13 @@ use {state, state_db, client, executive, trace, transaction, db, spec, pod_state use factory::Factories; use evm::{VMType, FinalizationResult}; use vm::{self, ActionParams}; +use ethtrie; /// EVM test Error. #[derive(Debug)] pub enum EvmTestError { /// Trie integrity error. - Trie(trie::TrieError), + Trie(Box), /// EVM error. Evm(vm::Error), /// Initialization error. diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 620f1af3330..3cb4660fe79 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -52,7 +52,6 @@ use miner::{self, Miner, MinerService}; use spec::Spec; use types::basic_account::BasicAccount; use types::pruning_info::PruningInfo; - use verification::queue::QueueInfo; use block::{OpenBlock, SealedBlock, ClosedBlock}; use executive::Executed; @@ -62,7 +61,7 @@ use state_db::StateDB; use header::Header; use encoded; use engines::EthEngine; -use trie; +use ethtrie; use state::StateInfo; use views::BlockView; @@ -581,10 +580,10 @@ impl Call for TestBlockChainClient { } impl StateInfo for () { - fn nonce(&self, _address: &Address) -> trie::Result { unimplemented!() } - fn balance(&self, _address: &Address) -> trie::Result { unimplemented!() } - fn storage_at(&self, _address: &Address, _key: &H256) -> trie::Result { unimplemented!() } - fn code(&self, _address: &Address) -> trie::Result>> { unimplemented!() } + fn nonce(&self, _address: &Address) -> ethtrie::Result { unimplemented!() } + fn balance(&self, _address: &Address) -> ethtrie::Result { unimplemented!() } + fn storage_at(&self, _address: &Address, _key: &H256) -> ethtrie::Result { unimplemented!() } + fn code(&self, _address: &Address) -> ethtrie::Result>> { unimplemented!() } } impl StateClient for TestBlockChainClient { diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index dee9c76025f..e927f77b715 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -16,12 +16,13 @@ //! A blockchain engine that supports a non-instant BFT proof-of-authority. +use std::collections::{BTreeMap, HashSet}; use std::fmt; +use std::iter::FromIterator; +use std::ops::Deref; use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering}; use std::sync::{Weak, Arc}; use std::time::{UNIX_EPOCH, SystemTime, Duration}; -use std::collections::{BTreeMap, HashSet}; -use std::iter::FromIterator; use account_provider::AccountProvider; use block::*; @@ -29,17 +30,14 @@ use client::EngineClient; use engines::{Engine, Seal, EngineError, ConstructedVerifier}; use engines::block_reward; use engines::block_reward::{BlockRewardContract, RewardKind}; -use error::{Error, BlockError}; +use error::{Error, ErrorKind, BlockError}; use ethjson; use machine::{AuxiliaryData, Call, EthereumMachine}; use hash::keccak; use header::{Header, BlockNumber, ExtendedHeader}; - use super::signer::EngineSigner; use super::validator_set::{ValidatorSet, SimpleList, new_validator_set}; - use self::finality::RollingFinality; - use ethkey::{self, Password, Signature}; use io::{IoContext, IoHandler, TimerToken, IoService}; use itertools::{self, Itertools}; @@ -575,7 +573,6 @@ fn verify_external(header: &Header, validators: &ValidatorSet, empty_steps_trans if is_invalid_proposer { trace!(target: "engine", "verify_block_external: bad proposer for step: {}", header_step); - validators.report_benign(header.author(), header.number(), header.number()); Err(EngineError::NotProposer(Mismatch { expected: correct_proposer, found: header.author().clone() }))? } else { Ok(()) @@ -607,6 +604,23 @@ impl AsMillis for Duration { } } +// A type for storing owned or borrowed data that has a common type. +// Useful for returning either a borrow or owned data from a function. +enum CowLike<'a, A: 'a + ?Sized, B> { + Borrowed(&'a A), + Owned(B), +} + +impl<'a, A: ?Sized, B> Deref for CowLike<'a, A, B> where B: AsRef { + type Target = A; + fn deref(&self) -> &A { + match self { + CowLike::Borrowed(b) => b, + CowLike::Owned(o) => o.as_ref(), + } + } +} + impl AuthorityRound { /// Create a new instance of AuthorityRound engine. pub fn new(our_params: AuthorityRoundParams, machine: EthereumMachine) -> Result, Error> { @@ -656,6 +670,30 @@ impl AuthorityRound { Ok(engine) } + // fetch correct validator set for epoch at header, taking into account + // finality of previous transitions. + fn epoch_set<'a>(&'a self, header: &Header) -> Result<(CowLike, BlockNumber), Error> { + Ok(if self.immediate_transitions { + (CowLike::Borrowed(&*self.validators), header.number()) + } else { + let mut epoch_manager = self.epoch_manager.lock(); + let client = match self.client.read().as_ref().and_then(|weak| weak.upgrade()) { + Some(client) => client, + None => { + debug!(target: "engine", "Unable to verify sig: missing client ref."); + return Err(EngineError::RequiresClient.into()) + } + }; + + if !epoch_manager.zoom_to(&*client, &self.machine, &*self.validators, header) { + debug!(target: "engine", "Unable to zoom to epoch."); + return Err(EngineError::RequiresClient.into()) + } + + (CowLike::Owned(epoch_manager.validators().clone()), epoch_manager.epoch_transition_number) + }) + } + fn empty_steps(&self, from_step: U256, to_step: U256, parent_hash: H256) -> Vec { self.empty_steps.lock().iter().filter(|e| { U256::from(e.step) > from_step && @@ -700,6 +738,28 @@ impl AuthorityRound { } } } + + fn report_skipped(&self, header: &Header, current_step: usize, parent_step: usize, validators: &ValidatorSet, set_number: u64) { + // we're building on top of the genesis block so don't report any skipped steps + if header.number() == 1 { + return; + } + + if let (true, Some(me)) = (current_step > parent_step + 1, self.signer.read().address()) { + debug!(target: "engine", "Author {} built block with step gap. current step: {}, parent step: {}", + header.author(), current_step, parent_step); + let mut reported = HashSet::new(); + for step in parent_step + 1..current_step { + let skipped_primary = step_proposer(validators, header.parent_hash(), step); + // Do not report this signer. + if skipped_primary != me { + // Stop reporting once validators start repeating. + if !reported.insert(skipped_primary) { break; } + self.validators.report_benign(&skipped_primary, set_number, header.number()); + } + } + } + } } fn unix_now() -> Duration { @@ -879,32 +939,15 @@ impl Engine for AuthorityRound { return Seal::None; } - // fetch correct validator set for current epoch, taking into account - // finality of previous transitions. - let active_set; - - let validators = if self.immediate_transitions { - &*self.validators - } else { - let mut epoch_manager = self.epoch_manager.lock(); - let client = match self.client.read().as_ref().and_then(|weak| weak.upgrade()) { - Some(client) => client, - None => { - warn!(target: "engine", "Unable to generate seal: missing client ref."); - return Seal::None; - } - }; - - if !epoch_manager.zoom_to(&*client, &self.machine, &*self.validators, header) { - debug!(target: "engine", "Unable to zoom to epoch."); + let (validators, set_number) = match self.epoch_set(header) { + Err(err) => { + warn!(target: "engine", "Unable to generate seal: {}", err); return Seal::None; - } - - active_set = epoch_manager.validators().clone(); - &active_set as &_ + }, + Ok(ok) => ok, }; - if is_step_proposer(validators, header.parent_hash(), step, header.author()) { + if is_step_proposer(&*validators, header.parent_hash(), step, header.author()) { // this is guarded against by `can_propose` unless the block was signed // on the same step (implies same key) and on a different node. if parent_step == step.into() { @@ -935,9 +978,15 @@ impl Engine for AuthorityRound { // only issue the seal if we were the first to reach the compare_and_swap. if self.step.can_propose.compare_and_swap(true, false, AtomicOrdering::SeqCst) { - + // we can drop all accumulated empty step messages that are + // older than the parent step since we're including them in + // the seal self.clear_empty_steps(parent_step); + // report any skipped primaries between the parent block and + // the block we're sealing + self.report_skipped(header, step, u64::from(parent_step) as usize, &*validators, set_number); + let mut fields = vec![ encode(&step).into_vec(), encode(&(&H520::from(signature) as &[u8])).into_vec(), @@ -1060,13 +1109,21 @@ impl Engine for AuthorityRound { ))); } - // TODO [ToDr] Should this go from epoch manager? - // If yes then probably benign reporting needs to be moved further in the verification. - let set_number = header.number(); - match verify_timestamp(&self.step.inner, header_step(header, self.empty_steps_transition)?) { Err(BlockError::InvalidSeal) => { - self.validators.report_benign(header.author(), set_number, header.number()); + // This check runs in Phase 1 where there is no guarantee that the parent block is + // already imported, therefore the call to `epoch_set` may fail. In that case we + // won't report the misbehavior but this is not a concern because: + // - Only authorities can report and it's expected that they'll be up-to-date and + // importing, therefore the parent header will most likely be available + // - Even if you are an authority that is syncing the chain, the contract will most + // likely ignore old reports + // - This specific check is only relevant if you're importing (since it checks + // against wall clock) + if let Ok((_, set_number)) = self.epoch_set(header) { + self.validators.report_benign(header.author(), set_number, header.number()); + } + Err(BlockError::InvalidSeal.into()) } Err(e) => Err(e.into()), @@ -1078,8 +1135,8 @@ impl Engine for AuthorityRound { fn verify_block_family(&self, header: &Header, parent: &Header) -> Result<(), Error> { let step = header_step(header, self.empty_steps_transition)?; let parent_step = header_step(parent, self.empty_steps_transition)?; - // TODO [ToDr] Should this go from epoch manager? - let set_number = header.number(); + + let (validators, set_number) = self.epoch_set(header)?; // Ensure header is from the step after parent. if step == parent_step @@ -1106,7 +1163,7 @@ impl Engine for AuthorityRound { format!("empty step proof for invalid parent hash: {:?}", empty_step.parent_hash)))?; } - if !empty_step.verify(&*self.validators).unwrap_or(false) { + if !empty_step.verify(&*validators).unwrap_or(false) { Err(EngineError::InsufficientProof( format!("invalid empty step proof: {:?}", empty_step)))?; } @@ -1120,21 +1177,7 @@ impl Engine for AuthorityRound { } } else { - // Report skipped primaries. - if let (true, Some(me)) = (step > parent_step + 1, self.signer.read().address()) { - debug!(target: "engine", "Author {} built block with step gap. current step: {}, parent step: {}", - header.author(), step, parent_step); - let mut reported = HashSet::new(); - for s in parent_step + 1..step { - let skipped_primary = step_proposer(&*self.validators, &parent.hash(), s); - // Do not report this signer. - if skipped_primary != me { - self.validators.report_benign(&skipped_primary, set_number, header.number()); - // Stop reporting once validators start repeating. - if !reported.insert(skipped_primary) { break; } - } - } - } + self.report_skipped(header, step, parent_step, &*validators, set_number); } Ok(()) @@ -1142,37 +1185,21 @@ impl Engine for AuthorityRound { // Check the validators. fn verify_block_external(&self, header: &Header) -> Result<(), Error> { - // fetch correct validator set for current epoch, taking into account - // finality of previous transitions. - let active_set; - let validators = if self.immediate_transitions { - &*self.validators - } else { - // get correct validator set for epoch. - let client = match self.client.read().as_ref().and_then(|weak| weak.upgrade()) { - Some(client) => client, - None => { - debug!(target: "engine", "Unable to verify sig: missing client ref."); - return Err(EngineError::RequiresClient.into()) - } - }; - - let mut epoch_manager = self.epoch_manager.lock(); - if !epoch_manager.zoom_to(&*client, &self.machine, &*self.validators, header) { - debug!(target: "engine", "Unable to zoom to epoch."); - return Err(EngineError::RequiresClient.into()) - } - - active_set = epoch_manager.validators().clone(); - &active_set as &_ - }; + let (validators, set_number) = self.epoch_set(header)?; // verify signature against fixed list, but reports should go to the // contract itself. - let res = verify_external(header, validators, self.empty_steps_transition); - if res.is_ok() { - let header_step = header_step(header, self.empty_steps_transition)?; - self.clear_empty_steps(header_step.into()); + let res = verify_external(header, &*validators, self.empty_steps_transition); + match res { + Err(Error(ErrorKind::Engine(EngineError::NotProposer(_)), _)) => { + self.validators.report_benign(header.author(), set_number, header.number()); + }, + Ok(_) => { + // we can drop all accumulated empty step messages that are older than this header's step + let header_step = header_step(header, self.empty_steps_transition)?; + self.clear_empty_steps(header_step.into()); + }, + _ => {}, } res } @@ -1581,7 +1608,6 @@ mod tests { parent_header.set_seal(vec![encode(&1usize).into_vec()]); parent_header.set_gas_limit("222222".parse::().unwrap()); let mut header: Header = Header::default(); - header.set_number(1); header.set_gas_limit("222222".parse::().unwrap()); header.set_seal(vec![encode(&3usize).into_vec()]); @@ -1591,8 +1617,15 @@ mod tests { aura.set_signer(Arc::new(AccountProvider::transient_provider()), Default::default(), "".into()); + // Do not report on steps skipped between genesis and first block. + header.set_number(1); + assert!(aura.verify_block_family(&header, &parent_header).is_ok()); + assert_eq!(last_benign.load(AtomicOrdering::SeqCst), 0); + + // Report on skipped steps otherwise. + header.set_number(2); assert!(aura.verify_block_family(&header, &parent_header).is_ok()); - assert_eq!(last_benign.load(AtomicOrdering::SeqCst), 1); + assert_eq!(last_benign.load(AtomicOrdering::SeqCst), 2); } #[test] diff --git a/ethcore/src/engines/tendermint/message.rs b/ethcore/src/engines/tendermint/message.rs index d7a08b303cf..7d76c32a275 100644 --- a/ethcore/src/engines/tendermint/message.rs +++ b/ethcore/src/engines/tendermint/message.rs @@ -16,15 +16,15 @@ //! Tendermint message handling. -use std::cmp; -use hash::keccak; -use ethereum_types::{H256, H520, Address}; use bytes::Bytes; -use super::{Height, View, BlockHash, Step}; use error::Error; +use ethereum_types::{H256, H520, Address}; +use ethkey::{recover, public_to_address}; +use hash::keccak; use header::Header; use rlp::{Rlp, RlpStream, Encodable, Decodable, DecoderError}; -use ethkey::{recover, public_to_address}; +use std::cmp; +use super::{Height, View, BlockHash, Step}; use super::super::vote_collector::Message; /// Message transmitted between consensus participants. diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 26b1cfd98f3..c95d61aa783 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -145,7 +145,7 @@ impl super::EpochVerifier for EpochVerifier fn check_finality_proof(&self, proof: &[u8]) -> Option> { match ::rlp::decode(proof) { Ok(header) => self.verify_light(&header).ok().map(|_| vec![header.hash()]), - Err(_) => None // REVIEW: log perhaps? Not sure what the policy is. + Err(_) => None } } } diff --git a/ethcore/src/engines/validator_set/mod.rs b/ethcore/src/engines/validator_set/mod.rs index 26b57d78f24..d7018d14e9a 100644 --- a/ethcore/src/engines/validator_set/mod.rs +++ b/ethcore/src/engines/validator_set/mod.rs @@ -53,7 +53,7 @@ pub fn new_validator_set(spec: ValidatorSpec) -> Box { } /// A validator set. -pub trait ValidatorSet: Send + Sync { +pub trait ValidatorSet: Send + Sync + 'static { /// Get the default "Call" helper, for use in general operation. // TODO [keorn]: this is a hack intended to migrate off of // a strict dependency on state always being available. diff --git a/ethcore/src/engines/validator_set/safe_contract.rs b/ethcore/src/engines/validator_set/safe_contract.rs index 2cecac8bda3..a7f4f2c731a 100644 --- a/ethcore/src/engines/validator_set/safe_contract.rs +++ b/ethcore/src/engines/validator_set/safe_contract.rs @@ -16,27 +16,23 @@ /// Validator set maintained in a contract, updated using `getValidators` method. -use std::sync::{Weak, Arc}; -use hash::keccak; - -use ethereum_types::{H256, U256, Address, Bloom}; -use parking_lot::RwLock; - use bytes::Bytes; -use memory_cache::MemoryLruCache; -use unexpected::Mismatch; -use rlp::{Rlp, RlpStream}; -use kvdb::DBValue; - use client::EngineClient; -use machine::{AuxiliaryData, Call, EthereumMachine, AuxiliaryRequest}; +use ethereum_types::{H256, U256, Address, Bloom}; +use hash::keccak; use header::Header; use ids::BlockId; +use kvdb::DBValue; use log_entry::LogEntry; +use machine::{AuxiliaryData, Call, EthereumMachine, AuxiliaryRequest}; +use memory_cache::MemoryLruCache; +use parking_lot::RwLock; use receipt::Receipt; - +use rlp::{Rlp, RlpStream}; +use std::sync::{Weak, Arc}; use super::{SystemCall, ValidatorSet}; use super::simple_list::SimpleList; +use unexpected::Mismatch; use_contract!(validator_set, "ValidatorSet", "res/contracts/validator_set.json"); diff --git a/ethcore/src/engines/validator_set/simple_list.rs b/ethcore/src/engines/validator_set/simple_list.rs index e1339250ef3..dc269600d00 100644 --- a/ethcore/src/engines/validator_set/simple_list.rs +++ b/ethcore/src/engines/validator_set/simple_list.rs @@ -104,6 +104,12 @@ impl ValidatorSet for SimpleList { } } +impl AsRef for SimpleList { + fn as_ref(&self) -> &ValidatorSet { + self + } +} + #[cfg(test)] mod tests { use std::str::FromStr; diff --git a/ethcore/src/error.rs b/ethcore/src/error.rs index bc8d6cc3305..88b50f8134f 100644 --- a/ethcore/src/error.rs +++ b/ethcore/src/error.rs @@ -19,10 +19,9 @@ use std::{fmt, error}; use std::time::SystemTime; use ethereum_types::{H256, U256, Address, Bloom}; -use util_error::{self, UtilError}; use snappy::InvalidInput; use unexpected::{Mismatch, OutOfBounds}; -use trie::TrieError; +use ethtrie::TrieError; use io::*; use header::BlockNumber; use client::Error as ClientError; @@ -206,7 +205,6 @@ impl From 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(), } } @@ -236,7 +234,6 @@ error_chain! { } links { - Util(UtilError, util_error::ErrorKind) #[doc = "Error concerning a utility"]; Import(ImportError, ImportErrorKind) #[doc = "Error concerning block import." ]; } @@ -326,7 +323,6 @@ impl From for Error { match err { BlockImportError(BlockImportErrorKind::Block(e), _) => ErrorKind::Block(e).into(), BlockImportError(BlockImportErrorKind::Import(e), _) => ErrorKind::Import(e).into(), - BlockImportError(BlockImportErrorKind::Other(s), _) => UtilError::from(s).into(), _ => ErrorKind::Msg(format!("other block import error: {:?}", err)).into(), } } diff --git a/ethcore/src/executed.rs b/ethcore/src/executed.rs index 3d0b9767c4a..2dc0c041be1 100644 --- a/ethcore/src/executed.rs +++ b/ethcore/src/executed.rs @@ -18,7 +18,7 @@ use ethereum_types::{U256, U512, Address}; use bytes::Bytes; -use trie; +use ethtrie; use vm; use trace::{VMTrace, FlatTrace}; use log_entry::LogEntry; @@ -117,9 +117,14 @@ pub enum ExecutionError { TransactionMalformed(String), } -impl From> for ExecutionError { - fn from(err: Box) -> Self { - ExecutionError::Internal(format!("{}", err)) +impl From> for ExecutionError { + fn from(err: Box) -> Self { + ExecutionError::Internal(format!("{:?}", err)) + } +} +impl From for ExecutionError { + fn from(err: ethtrie::TrieError) -> Self { + ExecutionError::Internal(format!("{:?}", err)) } } diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index f375f3c2e88..37dc03dee28 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -163,7 +163,7 @@ impl TransactOptions { } /// Transaction executor. -pub struct Executive<'a, B: 'a + StateBackend> { +pub struct Executive<'a, B: 'a> { state: &'a mut State, info: &'a EnvInfo, machine: &'a Machine, diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index 65d130c3422..d315122d56a 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -63,9 +63,7 @@ impl OriginInfo { } /// Implementation of evm Externalities. -pub struct Externalities<'a, T: 'a, V: 'a, B: 'a> - where T: Tracer, V: VMTracer, B: StateBackend -{ +pub struct Externalities<'a, T: 'a, V: 'a, B: 'a> { state: &'a mut State, env_info: &'a EnvInfo, machine: &'a Machine, diff --git a/ethcore/src/factory.rs b/ethcore/src/factory.rs index b429073b30c..2eff7d7605a 100644 --- a/ethcore/src/factory.rs +++ b/ethcore/src/factory.rs @@ -15,10 +15,12 @@ // along with Parity. If not, see . use trie::TrieFactory; +use ethtrie::RlpCodec; use account_db::Factory as AccountFactory; use evm::{Factory as EvmFactory, VMType}; use vm::{Vm, ActionParams, Schedule}; use wasm::WasmInterpreter; +use keccak_hasher::KeccakHasher; const WASM_MAGIC_NUMBER: &'static [u8; 4] = b"\0asm"; @@ -54,7 +56,7 @@ pub struct Factories { /// factory for evm. pub vm: VmFactory, /// factory for tries. - pub trie: TrieFactory, + pub trie: TrieFactory, /// factory for account databases. pub accountdb: AccountFactory, } diff --git a/ethcore/src/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index 86c6d6efcd2..daeed18ebfb 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -31,7 +31,7 @@ use ethjson; use trace::{Tracer, NoopTracer}; use trace::{VMTracer, NoopVMTracer}; use bytes::{Bytes, BytesRef}; -use trie; +use ethtrie; use rlp::RlpStream; use hash::keccak; use machine::EthereumMachine as Machine; @@ -93,7 +93,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> TestExt<'a, T, V, B> address: Address, tracer: &'a mut T, vm_tracer: &'a mut V, - ) -> trie::Result { + ) -> ethtrie::Result { let static_call = false; Ok(TestExt { nonce: state.nonce(&address)?, diff --git a/ethcore/src/json_tests/trie.rs b/ethcore/src/json_tests/trie.rs index 81bc5bcc012..0466c4de1f1 100644 --- a/ethcore/src/json_tests/trie.rs +++ b/ethcore/src/json_tests/trie.rs @@ -16,8 +16,10 @@ use ethjson; use trie::{TrieFactory, TrieSpec}; +use ethtrie::RlpCodec; use ethereum_types::H256; use memorydb::MemoryDB; +use keccak_hasher::KeccakHasher; use super::HookType; @@ -28,13 +30,13 @@ pub use self::secure::run_test_file as run_secure_test_file; fn test_trie(json: &[u8], trie: TrieSpec, start_stop_hook: &mut H) -> Vec { let tests = ethjson::trie::Test::load(json).unwrap(); - let factory = TrieFactory::new(trie); + let factory = TrieFactory::<_, RlpCodec>::new(trie); let mut result = vec![]; for (name, test) in tests.into_iter() { start_stop_hook(&name, HookType::OnStart); - let mut memdb = MemoryDB::new(); + let mut memdb = MemoryDB::::new(); let mut root = H256::default(); let mut t = factory.create(&mut memdb, &mut root); diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index f52afdcadec..70044bd09f0 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -70,6 +70,7 @@ extern crate ethcore_io as io; extern crate ethcore_bytes as bytes; extern crate ethcore_logger; extern crate ethcore_miner; +#[cfg(feature = "stratum")] extern crate ethcore_stratum; extern crate ethcore_transaction as transaction; extern crate ethereum_types; @@ -91,13 +92,14 @@ extern crate rayon; extern crate rlp; extern crate rlp_compress; extern crate keccak_hash as hash; +extern crate keccak_hasher; extern crate heapsize; extern crate memorydb; extern crate patricia_trie as trie; +extern crate patricia_trie_ethereum as ethtrie; extern crate triehash; extern crate ansi_term; extern crate unexpected; -extern crate util_error; extern crate snappy; extern crate ethabi; extern crate rustc_hex; diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index db496e40dc0..d196dc2f08c 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -14,8 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use std::cmp; use std::time::{Instant, Duration}; -use std::collections::{BTreeMap, HashSet, HashMap}; +use std::collections::{BTreeMap, BTreeSet, HashSet}; use std::sync::Arc; use ansi_term::Colour; @@ -24,6 +25,7 @@ use engines::{EthEngine, Seal}; use error::{Error, ErrorKind, ExecutionError}; use ethcore_miner::gas_pricer::GasPricer; use ethcore_miner::pool::{self, TransactionQueue, VerifiedTransaction, QueueStatus, PrioritizationStrategy}; +#[cfg(feature = "work-notify")] use ethcore_miner::work_notify::NotifyWork; use ethereum_types::{H256, U256, Address}; use parking_lot::{Mutex, RwLock}; @@ -46,7 +48,7 @@ use client::BlockId; use executive::contract_address; use header::{Header, BlockNumber}; use miner; -use miner::pool_client::{PoolClient, CachedNonceClient}; +use miner::pool_client::{PoolClient, CachedNonceClient, NonceCache}; use receipt::{Receipt, RichReceipt}; use spec::Spec; use state::State; @@ -200,8 +202,9 @@ pub struct Miner { // NOTE [ToDr] When locking always lock in this order! sealing: Mutex, params: RwLock, + #[cfg(feature = "work-notify")] listeners: RwLock>>, - nonce_cache: RwLock>, + nonce_cache: NonceCache, gas_pricer: Mutex, options: MinerOptions, // TODO [ToDr] Arc is only required because of price updater @@ -212,6 +215,7 @@ pub struct Miner { impl Miner { /// Push listener that will handle new jobs + #[cfg(feature = "work-notify")] pub fn add_work_listener(&self, notifier: Box) { self.listeners.write().push(notifier); self.sealing.lock().enabled = true; @@ -227,6 +231,7 @@ impl Miner { let limits = options.pool_limits.clone(); let verifier_options = options.pool_verification_options.clone(); let tx_queue_strategy = options.tx_queue_strategy; + let nonce_cache_size = cmp::max(4096, limits.max_count / 4); Miner { sealing: Mutex::new(SealingWork { @@ -238,9 +243,10 @@ impl Miner { last_request: None, }), params: RwLock::new(AuthoringParams::default()), + #[cfg(feature = "work-notify")] listeners: RwLock::new(vec![]), gas_pricer: Mutex::new(gas_pricer), - nonce_cache: RwLock::new(HashMap::with_capacity(1024)), + nonce_cache: NonceCache::new(nonce_cache_size), options, transaction_queue: Arc::new(TransactionQueue::new(limits, verifier_options, tx_queue_strategy)), accounts, @@ -491,7 +497,14 @@ impl Miner { /// 1. --force-sealing CLI parameter is provided /// 2. There are listeners awaiting new work packages (e.g. remote work notifications or stratum). fn forced_sealing(&self) -> bool { - self.options.force_sealing || !self.listeners.read().is_empty() + let listeners_empty = { + #[cfg(feature = "work-notify")] + { self.listeners.read().is_empty() } + #[cfg(not(feature = "work-notify"))] + { true } + }; + + self.options.force_sealing || !listeners_empty } /// Check is reseal is allowed and necessary. @@ -639,9 +652,13 @@ impl Miner { let is_new = original_work_hash.map_or(true, |h| h != block_hash); sealing.queue.push(block); - // If push notifications are enabled we assume all work items are used. - if is_new && !self.listeners.read().is_empty() { - sealing.queue.use_last_ref(); + + #[cfg(feature = "work-notify")] + { + // If push notifications are enabled we assume all work items are used. + if is_new && !self.listeners.read().is_empty() { + sealing.queue.use_last_ref(); + } } (Some((block_hash, *block_header.difficulty(), block_header.number())), is_new) @@ -655,12 +672,23 @@ impl Miner { ); (work, is_new) }; - if is_new { - work.map(|(pow_hash, difficulty, number)| { - for notifier in self.listeners.read().iter() { - notifier.notify(pow_hash, difficulty, number) - } - }); + + #[cfg(feature = "work-notify")] + { + if is_new { + work.map(|(pow_hash, difficulty, number)| { + for notifier in self.listeners.read().iter() { + notifier.notify(pow_hash, difficulty, number) + } + }); + } + } + + // NB: hack to use variables to avoid warning. + #[cfg(not(feature = "work-notify"))] + { + let _work = work; + let _is_new = is_new; } } @@ -851,6 +879,37 @@ impl miner::MinerService for Miner { self.transaction_queue.all_transactions() } + fn pending_transaction_hashes(&self, chain: &C) -> BTreeSet where + C: ChainInfo + Sync, + { + let chain_info = chain.chain_info(); + + let from_queue = || self.transaction_queue.pending_hashes( + |sender| self.nonce_cache.get(sender), + ); + + let from_pending = || { + self.map_existing_pending_block(|sealing| { + sealing.transactions() + .iter() + .map(|signed| signed.hash()) + .collect() + }, chain_info.best_block_number) + }; + + match self.options.pending_set { + PendingSet::AlwaysQueue => { + from_queue() + }, + PendingSet::AlwaysSealing => { + from_pending().unwrap_or_default() + }, + PendingSet::SealingOrElseQueue => { + from_pending().unwrap_or_else(from_queue) + }, + } + } + fn ready_transactions(&self, chain: &C, max_len: usize, ordering: miner::PendingOrdering) -> Vec> where @@ -1065,14 +1124,19 @@ impl miner::MinerService for Miner { // 2. We ignore blocks that are `invalid` because it doesn't have any meaning in terms of the transactions that // are in those blocks - // Clear nonce cache - self.nonce_cache.write().clear(); + let has_new_best_block = enacted.len() > 0; + + if has_new_best_block { + // Clear nonce cache + self.nonce_cache.clear(); + } // First update gas limit in transaction queue and minimal gas price. let gas_limit = *chain.best_block_header().gas_limit(); self.update_transaction_queue_limits(gas_limit); - // Then import all transactions... + + // Then import all transactions from retracted blocks. let client = self.pool_client(chain); { retracted @@ -1091,10 +1155,7 @@ impl miner::MinerService for Miner { }); } - // ...and at the end remove the old ones - self.transaction_queue.cull(client); - - if enacted.len() > 0 || (imported.len() > 0 && self.options.reseal_on_uncle) { + if has_new_best_block || (imported.len() > 0 && self.options.reseal_on_uncle) { // Reset `next_allowed_reseal` in case a block is imported. // Even if min_period is high, we will always attempt to create // new pending block. @@ -1108,6 +1169,15 @@ impl miner::MinerService for Miner { self.update_sealing(chain); } } + + if has_new_best_block { + // Make sure to cull transactions after we update sealing. + // Not culling won't lead to old transactions being added to the block + // (thanks to Ready), but culling can take significant amount of time, + // so best to leave it after we create some work for miners to prevent increased + // uncle rate. + self.transaction_queue.cull(client); + } } fn pending_state(&self, latest_block_number: BlockNumber) -> Option { @@ -1405,6 +1475,7 @@ mod tests { assert!(!miner.is_currently_sealing()); } + #[cfg(feature = "work-notify")] #[test] fn should_mine_if_fetch_work_request() { struct DummyNotifyWork; diff --git a/ethcore/src/miner/mod.rs b/ethcore/src/miner/mod.rs index 44d9ecf71af..cc56bf01f94 100644 --- a/ethcore/src/miner/mod.rs +++ b/ethcore/src/miner/mod.rs @@ -23,13 +23,14 @@ mod miner; mod service_transaction_checker; pub mod pool_client; +#[cfg(feature = "stratum")] pub mod stratum; pub use self::miner::{Miner, MinerOptions, Penalization, PendingSet, AuthoringParams}; pub use ethcore_miner::pool::PendingOrdering; use std::sync::Arc; -use std::collections::BTreeMap; +use std::collections::{BTreeSet, BTreeMap}; use bytes::Bytes; use ethereum_types::{H256, U256, Address}; @@ -164,6 +165,12 @@ pub trait MinerService : Send + Sync { fn next_nonce(&self, chain: &C, address: &Address) -> U256 where C: Nonce + Sync; + /// Get a set of all pending transaction hashes. + /// + /// Depending on the settings may look in transaction pool or only in pending block. + fn pending_transaction_hashes(&self, chain: &C) -> BTreeSet where + C: ChainInfo + Sync; + /// Get a list of all ready transactions either ordered by priority or unordered (cheaper). /// /// Depending on the settings may look in transaction pool or only in pending block. diff --git a/ethcore/src/miner/pool_client.rs b/ethcore/src/miner/pool_client.rs index bcf93d37532..f537a2757e2 100644 --- a/ethcore/src/miner/pool_client.rs +++ b/ethcore/src/miner/pool_client.rs @@ -36,10 +36,32 @@ use header::Header; use miner; use miner::service_transaction_checker::ServiceTransactionChecker; -type NoncesCache = RwLock>; +/// Cache for state nonces. +#[derive(Debug)] +pub struct NonceCache { + nonces: RwLock>, + limit: usize +} + +impl NonceCache { + /// Create new cache with a limit of `limit` entries. + pub fn new(limit: usize) -> Self { + NonceCache { + nonces: RwLock::new(HashMap::with_capacity(limit / 2)), + limit, + } + } + + /// Retrieve a cached nonce for given sender. + pub fn get(&self, sender: &Address) -> Option { + self.nonces.read().get(sender).cloned() + } -const MAX_NONCE_CACHE_SIZE: usize = 4096; -const EXPECTED_NONCE_CACHE_SIZE: usize = 2048; + /// Clear all entries from the cache. + pub fn clear(&self) { + self.nonces.write().clear(); + } +} /// Blockchain accesss for transaction pool. pub struct PoolClient<'a, C: 'a> { @@ -70,7 +92,7 @@ C: BlockInfo + CallContract, /// Creates new client given chain, nonce cache, accounts and service transaction verifier. pub fn new( chain: &'a C, - cache: &'a NoncesCache, + cache: &'a NonceCache, engine: &'a EthEngine, accounts: Option<&'a AccountProvider>, refuse_service_transactions: bool, @@ -161,7 +183,7 @@ impl<'a, C: 'a> NonceClient for PoolClient<'a, C> where pub(crate) struct CachedNonceClient<'a, C: 'a> { client: &'a C, - cache: &'a NoncesCache, + cache: &'a NonceCache, } impl<'a, C: 'a> Clone for CachedNonceClient<'a, C> { @@ -176,13 +198,14 @@ impl<'a, C: 'a> Clone for CachedNonceClient<'a, C> { impl<'a, C: 'a> fmt::Debug for CachedNonceClient<'a, C> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("CachedNonceClient") - .field("cache", &self.cache.read().len()) + .field("cache", &self.cache.nonces.read().len()) + .field("limit", &self.cache.limit) .finish() } } impl<'a, C: 'a> CachedNonceClient<'a, C> { - pub fn new(client: &'a C, cache: &'a NoncesCache) -> Self { + pub fn new(client: &'a C, cache: &'a NonceCache) -> Self { CachedNonceClient { client, cache, @@ -194,27 +217,29 @@ impl<'a, C: 'a> NonceClient for CachedNonceClient<'a, C> where C: Nonce + Sync, { fn account_nonce(&self, address: &Address) -> U256 { - if let Some(nonce) = self.cache.read().get(address) { + if let Some(nonce) = self.cache.nonces.read().get(address) { return *nonce; } // We don't check again if cache has been populated. // It's not THAT expensive to fetch the nonce from state. - let mut cache = self.cache.write(); + let mut cache = self.cache.nonces.write(); let nonce = self.client.latest_nonce(address); cache.insert(*address, nonce); - if cache.len() < MAX_NONCE_CACHE_SIZE { + if cache.len() < self.cache.limit { return nonce } + debug!(target: "txpool", "NonceCache: reached limit."); + trace_time!("nonce_cache:clear"); + // Remove excessive amount of entries from the cache - while cache.len() > EXPECTED_NONCE_CACHE_SIZE { - // Just remove random entry - if let Some(key) = cache.keys().next().cloned() { - cache.remove(&key); - } + let to_remove: Vec<_> = cache.keys().take(self.cache.limit / 2).cloned().collect(); + for x in to_remove { + cache.remove(&x); } + nonce } } diff --git a/ethcore/src/miner/stratum.rs b/ethcore/src/miner/stratum.rs index 0fd892bf50b..ca74432790f 100644 --- a/ethcore/src/miner/stratum.rs +++ b/ethcore/src/miner/stratum.rs @@ -24,10 +24,12 @@ use client::{Client, ImportSealedBlock}; use ethereum_types::{H64, H256, clean_0x, U256}; use ethereum::ethash::Ethash; use ethash::SeedHashCompute; +#[cfg(feature = "work-notify")] use ethcore_miner::work_notify::NotifyWork; +#[cfg(feature = "work-notify")] +use ethcore_stratum::PushWorkHandler; use ethcore_stratum::{ - JobDispatcher, PushWorkHandler, - Stratum as StratumService, Error as StratumServiceError, + JobDispatcher, Stratum as StratumService, Error as StratumServiceError, }; use miner::{Miner, MinerService}; use parking_lot::Mutex; @@ -156,7 +158,7 @@ impl StratumJobDispatcher { /// New stratum job dispatcher given the miner and client fn new(miner: Weak, client: Weak) -> StratumJobDispatcher { StratumJobDispatcher { - seed_compute: Mutex::new(SeedHashCompute::new()), + seed_compute: Mutex::new(SeedHashCompute::default()), client: client, miner: miner, } @@ -209,6 +211,7 @@ impl From for Error { fn from(err: AddrParseError) -> Error { Error::Address(err) } } +#[cfg(feature = "work-notify")] impl NotifyWork for Stratum { fn notify(&self, pow_hash: H256, difficulty: U256, number: u64) { trace!(target: "stratum", "Notify work"); @@ -242,6 +245,7 @@ impl Stratum { } /// Start STRATUM job dispatcher and register it in the miner + #[cfg(feature = "work-notify")] pub fn register(cfg: &Options, miner: Arc, client: Weak) -> Result<(), Error> { let stratum = Stratum::start(cfg, Arc::downgrade(&miner.clone()), client)?; miner.add_work_listener(Box::new(stratum) as Box); diff --git a/ethcore/src/pod_account.rs b/ethcore/src/pod_account.rs index 281299b3b22..f35f0517780 100644 --- a/ethcore/src/pod_account.rs +++ b/ethcore/src/pod_account.rs @@ -20,9 +20,11 @@ use itertools::Itertools; use hash::{keccak}; use ethereum_types::{H256, U256}; use hashdb::HashDB; +use keccak_hasher::KeccakHasher; use triehash::sec_trie_root; use bytes::Bytes; use trie::TrieFactory; +use ethtrie::RlpCodec; use state::Account; use ethjson; use types::account_diff::*; @@ -65,7 +67,7 @@ impl PodAccount { } /// Place additional data into given hash DB. - pub fn insert_additional(&self, db: &mut HashDB, factory: &TrieFactory) { + pub fn insert_additional(&self, db: &mut HashDB, factory: &TrieFactory) { match self.code { Some(ref c) if !c.is_empty() => { db.insert(c); } _ => {} diff --git a/ethcore/src/snapshot/account.rs b/ethcore/src/snapshot/account.rs index 71c10068fe7..13ab4b227ff 100644 --- a/ethcore/src/snapshot/account.rs +++ b/ethcore/src/snapshot/account.rs @@ -18,16 +18,15 @@ use account_db::{AccountDB, AccountDBMut}; use basic_account::BasicAccount; -use snapshot::Error; -use hash::{KECCAK_EMPTY, KECCAK_NULL_RLP}; - +use bytes::Bytes; use ethereum_types::{H256, U256}; +use ethtrie::{TrieDB, TrieDBMut}; +use hash::{KECCAK_EMPTY, KECCAK_NULL_RLP}; use hashdb::HashDB; -use bytes::Bytes; -use trie::{TrieDB, Trie}; use rlp::{RlpStream, Rlp}; - +use snapshot::Error; use std::collections::HashSet; +use trie::{Trie, TrieMut}; // An empty account -- these were replaced with RLP null data for a space optimization in v1. const ACC_EMPTY: BasicAccount = BasicAccount { @@ -151,7 +150,6 @@ pub fn from_fat_rlp( rlp: Rlp, mut storage_root: H256, ) -> Result<(BasicAccount, Option), Error> { - use trie::{TrieDBMut, TrieMut}; // check for special case of empty account. if rlp.is_empty() { diff --git a/ethcore/src/snapshot/block.rs b/ethcore/src/snapshot/block.rs index cec2e491a70..3a18015e0c5 100644 --- a/ethcore/src/snapshot/block.rs +++ b/ethcore/src/snapshot/block.rs @@ -19,7 +19,6 @@ use block::Block; use header::Header; use hash::keccak; - use views::BlockView; use rlp::{DecoderError, RlpStream, Rlp}; use ethereum_types::H256; diff --git a/ethcore/src/snapshot/consensus/authority.rs b/ethcore/src/snapshot/consensus/authority.rs index 7adaf834056..8ae4cc33c0c 100644 --- a/ethcore/src/snapshot/consensus/authority.rs +++ b/ethcore/src/snapshot/consensus/authority.rs @@ -38,6 +38,7 @@ use ethereum_types::{H256, U256}; use kvdb::KeyValueDB; use bytes::Bytes; + /// Snapshot creation and restoration for PoA chains. /// Chunk format: /// diff --git a/ethcore/src/snapshot/error.rs b/ethcore/src/snapshot/error.rs index 36fb0927a6b..527b4e2882c 100644 --- a/ethcore/src/snapshot/error.rs +++ b/ethcore/src/snapshot/error.rs @@ -21,7 +21,7 @@ use std::fmt; use ids::BlockId; use ethereum_types::H256; -use trie::TrieError; +use ethtrie::TrieError; use rlp::DecoderError; /// Snapshot-related errors. diff --git a/ethcore/src/snapshot/mod.rs b/ethcore/src/snapshot/mod.rs index 30a61b779cc..f4b9bf69970 100644 --- a/ethcore/src/snapshot/mod.rs +++ b/ethcore/src/snapshot/mod.rs @@ -32,13 +32,15 @@ use ids::BlockId; use ethereum_types::{H256, U256}; use hashdb::HashDB; +use keccak_hasher::KeccakHasher; use kvdb::DBValue; use snappy; use bytes::Bytes; use parking_lot::Mutex; use journaldb::{self, Algorithm, JournalDB}; use kvdb::KeyValueDB; -use trie::{TrieDB, TrieDBMut, Trie, TrieMut}; +use trie::{Trie, TrieMut}; +use ethtrie::{TrieDB, TrieDBMut}; use rlp::{RlpStream, Rlp}; use bloom_journal::Bloom; @@ -126,7 +128,7 @@ pub fn take_snapshot( engine: &EthEngine, chain: &BlockChain, block_at: H256, - state_db: &HashDB, + state_db: &HashDB, writer: W, p: &Progress ) -> Result<(), Error> { @@ -264,7 +266,7 @@ impl<'a> StateChunker<'a> { /// /// Returns a list of hashes of chunks created, or any error it may /// have encountered. -pub fn chunk_state<'a>(db: &HashDB, root: &H256, writer: &Mutex, progress: &'a Progress) -> Result, Error> { +pub fn chunk_state<'a>(db: &HashDB, root: &H256, writer: &Mutex, progress: &'a Progress) -> Result, Error> { let account_trie = TrieDB::new(db, &root)?; let mut chunker = StateChunker { @@ -414,7 +416,7 @@ struct RebuiltStatus { // rebuild a set of accounts and their storage. // returns a status detailing newly-loaded code and accounts missing code. fn rebuild_accounts( - db: &mut HashDB, + db: &mut HashDB, account_fat_rlps: Rlp, out_chunk: &mut [(H256, Bytes)], known_code: &HashMap, diff --git a/ethcore/src/snapshot/service.rs b/ethcore/src/snapshot/service.rs index 14d9be8f4bb..2e76153cff4 100644 --- a/ethcore/src/snapshot/service.rs +++ b/ethcore/src/snapshot/service.rs @@ -37,7 +37,6 @@ use io::IoChannel; use ethereum_types::H256; use parking_lot::{Mutex, RwLock, RwLockReadGuard}; -use util_error::UtilError; use bytes::Bytes; use journaldb::Algorithm; use snappy; @@ -621,7 +620,7 @@ impl Service { match is_done { true => { - db.key_value().flush().map_err(UtilError::from)?; + db.key_value().flush()?; drop(db); return self.finalize_restoration(&mut *restoration); }, @@ -634,7 +633,10 @@ impl Service { } } }; - result.and_then(|_| db.key_value().flush().map_err(|e| UtilError::from(e).into())) + + result?; + db.key_value().flush()?; + Ok(()) } /// Feed a state chunk to be processed synchronously. diff --git a/ethcore/src/snapshot/tests/helpers.rs b/ethcore/src/snapshot/tests/helpers.rs index f01cad45cdf..19f50e94690 100644 --- a/ethcore/src/snapshot/tests/helpers.rs +++ b/ethcore/src/snapshot/tests/helpers.rs @@ -36,8 +36,10 @@ use rand::Rng; use kvdb::DBValue; use ethereum_types::H256; use hashdb::HashDB; +use keccak_hasher::KeccakHasher; use journaldb; -use trie::{SecTrieDBMut, TrieMut, TrieDB, TrieDBMut, Trie}; +use trie::{TrieMut, Trie}; +use ethtrie::{SecTrieDBMut, TrieDB, TrieDBMut}; use self::trie_standardmap::{Alphabet, StandardMap, ValueMode}; // the proportion of accounts we will alter each tick. @@ -60,7 +62,7 @@ impl StateProducer { /// Tick the state producer. This alters the state, writing new data into /// the database. - pub fn tick(&mut self, rng: &mut R, db: &mut HashDB) { + pub fn tick(&mut self, rng: &mut R, db: &mut HashDB) { // modify existing accounts. let mut accounts_to_modify: Vec<_> = { let trie = TrieDB::new(&*db, &self.state_root).unwrap(); @@ -129,7 +131,7 @@ pub fn fill_storage(mut db: AccountDBMut, root: &mut H256, seed: &mut H256) { } /// Compare two state dbs. -pub fn compare_dbs(one: &HashDB, two: &HashDB) { +pub fn compare_dbs(one: &HashDB, two: &HashDB) { let keys = one.keys(); for key in keys.keys() { diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 6f785fe7fba..e8c316be5f2 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -81,11 +81,11 @@ pub struct CommonParams { /// EIP150 transition block number. pub eip150_transition: BlockNumber, /// Number of first block where EIP-160 rules begin. - pub eip160_transition: u64, + pub eip160_transition: BlockNumber, /// Number of first block where EIP-161.abc begin. - pub eip161abc_transition: u64, + pub eip161abc_transition: BlockNumber, /// Number of first block where EIP-161.d begins. - pub eip161d_transition: u64, + pub eip161d_transition: BlockNumber, /// Number of first block where EIP-98 rules begin. pub eip98_transition: BlockNumber, /// Number of first block where EIP-658 rules begin. diff --git a/ethcore/src/state/account.rs b/ethcore/src/state/account.rs index a7a40e6a3bb..359b84b1eca 100644 --- a/ethcore/src/state/account.rs +++ b/ethcore/src/state/account.rs @@ -23,10 +23,11 @@ use hash::{KECCAK_EMPTY, KECCAK_NULL_RLP, keccak}; use ethereum_types::{H256, U256, Address}; use error::Error; use hashdb::HashDB; +use keccak_hasher::KeccakHasher; use kvdb::DBValue; use bytes::{Bytes, ToPretty}; -use trie; -use trie::{SecTrieDB, Trie, TrieFactory, TrieError}; +use trie::{Trie, Recorder}; +use ethtrie::{TrieFactory, TrieDB, SecTrieDB, Result as TrieResult}; use pod_account::*; use rlp::{RlpStream, encode}; use lru_cache::LruCache; @@ -199,7 +200,7 @@ impl Account { /// Get (and cache) the contents of the trie's storage at `key`. /// Takes modified storage into account. - pub fn storage_at(&self, db: &HashDB, key: &H256) -> trie::Result { + pub fn storage_at(&self, db: &HashDB, key: &H256) -> TrieResult { if let Some(value) = self.cached_storage_at(key) { return Ok(value); } @@ -278,7 +279,7 @@ impl Account { } /// Provide a database to get `code_hash`. Should not be called if it is a contract without code. - pub fn cache_code(&mut self, db: &HashDB) -> Option> { + pub fn cache_code(&mut self, db: &HashDB) -> Option> { // TODO: fill out self.code_cache; trace!("Account::cache_code: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty()); @@ -307,7 +308,7 @@ impl Account { } /// Provide a database to get `code_size`. Should not be called if it is a contract without code. - pub fn cache_code_size(&mut self, db: &HashDB) -> bool { + pub fn cache_code_size(&mut self, db: &HashDB) -> bool { // TODO: fill out self.code_cache; trace!("Account::cache_code_size: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty()); self.code_size.is_some() || @@ -374,7 +375,7 @@ impl Account { } /// Commit the `storage_changes` to the backing DB and update `storage_root`. - pub fn commit_storage(&mut self, trie_factory: &TrieFactory, db: &mut HashDB) -> trie::Result<()> { + pub fn commit_storage(&mut self, trie_factory: &TrieFactory, db: &mut HashDB) -> TrieResult<()> { let mut t = trie_factory.from_existing(db, &mut self.storage_root)?; for (k, v) in self.storage_changes.drain() { // cast key and value to trait type, @@ -390,7 +391,7 @@ impl Account { } /// Commit any unsaved code. `code_hash` will always return the hash of the `code_cache` after this. - pub fn commit_code(&mut self, db: &mut HashDB) { + pub fn commit_code(&mut self, db: &mut HashDB) { trace!("Commiting code of {:?} - {:?}, {:?}", self, self.code_filth == Filth::Dirty, self.code_cache.is_empty()); match (self.code_filth == Filth::Dirty, self.code_cache.is_empty()) { (true, true) => { @@ -472,10 +473,7 @@ impl Account { /// trie. /// `storage_key` is the hash of the desired storage key, meaning /// this will only work correctly under a secure trie. - pub fn prove_storage(&self, db: &HashDB, storage_key: H256) -> Result<(Vec, H256), Box> { - use trie::{Trie, TrieDB}; - use trie::recorder::Recorder; - + pub fn prove_storage(&self, db: &HashDB, storage_key: H256) -> TrieResult<(Vec, H256)> { let mut recorder = Recorder::new(); let trie = TrieDB::new(db, &self.storage_root)?; diff --git a/ethcore/src/state/backend.rs b/ethcore/src/state/backend.rs index 6b2e21cb465..d07124d8d70 100644 --- a/ethcore/src/state/backend.rs +++ b/ethcore/src/state/backend.rs @@ -29,14 +29,15 @@ use parking_lot::Mutex; use ethereum_types::{Address, H256}; use memorydb::MemoryDB; use hashdb::{AsHashDB, HashDB, DBValue}; +use keccak_hasher::KeccakHasher; /// State backend. See module docs for more details. pub trait Backend: Send { /// Treat the backend as a read-only hashdb. - fn as_hashdb(&self) -> &HashDB; + fn as_hashdb(&self) -> &HashDB; /// Treat the backend as a writeable hashdb. - fn as_hashdb_mut(&mut self) -> &mut HashDB; + fn as_hashdb_mut(&mut self) -> &mut HashDB; /// Add an account entry to the cache. fn add_to_account_cache(&mut self, addr: Address, data: Option, modified: bool); @@ -75,18 +76,18 @@ pub trait Backend: Send { // TODO: when account lookup moved into backends, this won't rely as tenuously on intended // usage. #[derive(Clone, PartialEq)] -pub struct ProofCheck(MemoryDB); +pub struct ProofCheck(MemoryDB); impl ProofCheck { /// Create a new `ProofCheck` backend from the given state items. pub fn new(proof: &[DBValue]) -> Self { - let mut db = MemoryDB::new(); + let mut db = MemoryDB::::new(); for item in proof { db.insert(item); } ProofCheck(db) } } -impl HashDB for ProofCheck { +impl HashDB for ProofCheck { fn keys(&self) -> HashMap { self.0.keys() } fn get(&self, key: &H256) -> Option { self.0.get(key) @@ -107,9 +108,14 @@ impl HashDB for ProofCheck { fn remove(&mut self, _key: &H256) { } } +impl AsHashDB for ProofCheck { + fn as_hashdb(&self) -> &HashDB { self } + fn as_hashdb_mut(&mut self) -> &mut HashDB { self } +} + impl Backend for ProofCheck { - fn as_hashdb(&self) -> &HashDB { self } - fn as_hashdb_mut(&mut self) -> &mut HashDB { self } + fn as_hashdb(&self) -> &HashDB { self } + fn as_hashdb_mut(&mut self) -> &mut HashDB { self } fn add_to_account_cache(&mut self, _addr: Address, _data: Option, _modified: bool) {} fn cache_code(&self, _hash: H256, _code: Arc>) {} fn get_cached_account(&self, _addr: &Address) -> Option> { None } @@ -128,13 +134,18 @@ impl Backend for ProofCheck { /// The proof-of-execution can be extracted with `extract_proof`. /// /// This doesn't cache anything or rely on the canonical state caches. -pub struct Proving { +pub struct Proving> { base: H, // state we're proving values from. - changed: MemoryDB, // changed state via insertions. + changed: MemoryDB, // changed state via insertions. proof: Mutex>, } -impl HashDB for Proving { +impl + Send + Sync> AsHashDB for Proving { + fn as_hashdb(&self) -> &HashDB { self } + fn as_hashdb_mut(&mut self) -> &mut HashDB { self } +} + +impl + Send + Sync> HashDB for Proving { fn keys(&self) -> HashMap { let mut keys = self.base.as_hashdb().keys(); keys.extend(self.changed.keys()); @@ -171,14 +182,10 @@ impl HashDB for Proving { } } -impl Backend for Proving { - fn as_hashdb(&self) -> &HashDB { - self - } +impl + Send + Sync> Backend for Proving { + fn as_hashdb(&self) -> &HashDB { self } - fn as_hashdb_mut(&mut self) -> &mut HashDB { - self - } + fn as_hashdb_mut(&mut self) -> &mut HashDB { self } fn add_to_account_cache(&mut self, _: Address, _: Option, _: bool) { } @@ -197,13 +204,13 @@ impl Backend for Proving { fn is_known_null(&self, _: &Address) -> bool { false } } -impl Proving { +impl> Proving { /// Create a new `Proving` over a base database. /// This will store all values ever fetched from that base. pub fn new(base: H) -> Self { Proving { base: base, - changed: MemoryDB::new(), + changed: MemoryDB::::new(), proof: Mutex::new(HashSet::new()), } } @@ -215,7 +222,7 @@ impl Proving { } } -impl Clone for Proving { +impl + Clone> Clone for Proving { fn clone(&self) -> Self { Proving { base: self.base.clone(), @@ -229,12 +236,12 @@ impl Clone for Proving { /// it. Doesn't cache anything. pub struct Basic(pub H); -impl Backend for Basic { - fn as_hashdb(&self) -> &HashDB { +impl + Send + Sync> Backend for Basic { + fn as_hashdb(&self) -> &HashDB { self.0.as_hashdb() } - fn as_hashdb_mut(&mut self) -> &mut HashDB { + fn as_hashdb_mut(&mut self) -> &mut HashDB { self.0.as_hashdb_mut() } diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index ccca20b71e1..0da61425442 100644 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -44,12 +44,12 @@ use factory::VmFactory; use ethereum_types::{H256, U256, Address}; use hashdb::{HashDB, AsHashDB}; +use keccak_hasher::KeccakHasher; use kvdb::DBValue; use bytes::Bytes; -use trie; -use trie::{Trie, TrieError, TrieDB}; -use trie::recorder::Recorder; +use trie::{Trie, TrieError, Recorder}; +use ethtrie::{TrieDB, Result as TrieResult}; mod account; mod substate; @@ -225,7 +225,7 @@ pub fn check_proof( /// Prove a transaction on the given state. /// Returns `None` when the transacion could not be proved, /// and a proof otherwise. -pub fn prove_transaction( +pub fn prove_transaction + Send + Sync>( db: H, root: H256, transaction: &SignedTransaction, @@ -305,7 +305,7 @@ pub fn prove_transaction( /// checkpoint can be discarded with `discard_checkpoint`. All of the orignal /// backed-up values are moved into a parent checkpoint (if any). /// -pub struct State { +pub struct State { db: B, root: H256, cache: RefCell>, @@ -336,23 +336,23 @@ pub enum CleanupMode<'a> { /// Provides subset of `State` methods to query state information pub trait StateInfo { /// Get the nonce of account `a`. - fn nonce(&self, a: &Address) -> trie::Result; + fn nonce(&self, a: &Address) -> TrieResult; /// Get the balance of account `a`. - fn balance(&self, a: &Address) -> trie::Result; + fn balance(&self, a: &Address) -> TrieResult; /// Mutate storage of account `address` so that it is `value` for `key`. - fn storage_at(&self, address: &Address, key: &H256) -> trie::Result; + fn storage_at(&self, address: &Address, key: &H256) -> TrieResult; /// Get accounts' code. - fn code(&self, a: &Address) -> trie::Result>>; + fn code(&self, a: &Address) -> TrieResult>>; } impl StateInfo for State { - fn nonce(&self, a: &Address) -> trie::Result { State::nonce(self, a) } - fn balance(&self, a: &Address) -> trie::Result { State::balance(self, a) } - fn storage_at(&self, address: &Address, key: &H256) -> trie::Result { State::storage_at(self, address, key) } - fn code(&self, address: &Address) -> trie::Result>> { State::code(self, address) } + fn nonce(&self, a: &Address) -> TrieResult { State::nonce(self, a) } + fn balance(&self, a: &Address) -> TrieResult { State::balance(self, a) } + fn storage_at(&self, address: &Address, key: &H256) -> TrieResult { State::storage_at(self, address, key) } + fn code(&self, address: &Address) -> TrieResult>> { State::code(self, address) } } const SEC_TRIE_DB_UNWRAP_STR: &'static str = "A state can only be created with valid root. Creating a SecTrieDB with a valid root will not fail. \ @@ -379,9 +379,9 @@ impl State { } /// Creates new state with existing state root - pub fn from_existing(db: B, root: H256, account_start_nonce: U256, factories: Factories) -> Result, TrieError> { + pub fn from_existing(db: B, root: H256, account_start_nonce: U256, factories: Factories) -> TrieResult> { if !db.as_hashdb().contains(&root) { - return Err(TrieError::InvalidStateRoot(root)); + return Err(Box::new(TrieError::InvalidStateRoot(root))); } let state = State { @@ -481,7 +481,7 @@ impl State { } /// Destroy the current object and return single account data. - pub fn into_account(self, account: &Address) -> trie::Result<(Option>, HashMap)> { + pub fn into_account(self, account: &Address) -> TrieResult<(Option>, HashMap)> { // TODO: deconstruct without cloning. let account = self.require(account, true)?; Ok((account.code().clone(), account.storage_changes().clone())) @@ -504,43 +504,43 @@ impl State { } /// Determine whether an account exists. - pub fn exists(&self, a: &Address) -> trie::Result { + pub fn exists(&self, a: &Address) -> TrieResult { // Bloom filter does not contain empty accounts, so it is important here to // check if account exists in the database directly before EIP-161 is in effect. self.ensure_cached(a, RequireCache::None, false, |a| a.is_some()) } /// Determine whether an account exists and if not empty. - pub fn exists_and_not_null(&self, a: &Address) -> trie::Result { + pub fn exists_and_not_null(&self, a: &Address) -> TrieResult { self.ensure_cached(a, RequireCache::None, false, |a| a.map_or(false, |a| !a.is_null())) } /// Determine whether an account exists and has code or non-zero nonce. - pub fn exists_and_has_code_or_nonce(&self, a: &Address) -> trie::Result { + pub fn exists_and_has_code_or_nonce(&self, a: &Address) -> TrieResult { self.ensure_cached(a, RequireCache::CodeSize, false, |a| a.map_or(false, |a| a.code_hash() != KECCAK_EMPTY || *a.nonce() != self.account_start_nonce)) } /// Get the balance of account `a`. - pub fn balance(&self, a: &Address) -> trie::Result { + pub fn balance(&self, a: &Address) -> TrieResult { self.ensure_cached(a, RequireCache::None, true, |a| a.as_ref().map_or(U256::zero(), |account| *account.balance())) } /// Get the nonce of account `a`. - pub fn nonce(&self, a: &Address) -> trie::Result { + pub fn nonce(&self, a: &Address) -> TrieResult { self.ensure_cached(a, RequireCache::None, true, |a| a.as_ref().map_or(self.account_start_nonce, |account| *account.nonce())) } /// Get the storage root of account `a`. - pub fn storage_root(&self, a: &Address) -> trie::Result> { + pub fn storage_root(&self, a: &Address) -> TrieResult> { self.ensure_cached(a, RequireCache::None, true, |a| a.as_ref().and_then(|account| account.storage_root().cloned())) } /// Mutate storage of account `address` so that it is `value` for `key`. - pub fn storage_at(&self, address: &Address, key: &H256) -> trie::Result { + pub fn storage_at(&self, address: &Address, key: &H256) -> TrieResult { // Storage key search and update works like this: // 1. If there's an entry for the account in the local cache check for the key and return it if found. // 2. If there's an entry for the account in the global cache check for the key or load it into that account. @@ -602,25 +602,25 @@ impl State { } /// Get accounts' code. - pub fn code(&self, a: &Address) -> trie::Result>> { + pub fn code(&self, a: &Address) -> TrieResult>> { self.ensure_cached(a, RequireCache::Code, true, |a| a.as_ref().map_or(None, |a| a.code().clone())) } /// Get an account's code hash. - pub fn code_hash(&self, a: &Address) -> trie::Result { + pub fn code_hash(&self, a: &Address) -> TrieResult { self.ensure_cached(a, RequireCache::None, true, |a| a.as_ref().map_or(KECCAK_EMPTY, |a| a.code_hash())) } /// Get accounts' code size. - pub fn code_size(&self, a: &Address) -> trie::Result> { + pub fn code_size(&self, a: &Address) -> TrieResult> { self.ensure_cached(a, RequireCache::CodeSize, true, |a| a.as_ref().and_then(|a| a.code_size())) } /// Add `incr` to the balance of account `a`. - pub fn add_balance(&mut self, a: &Address, incr: &U256, cleanup_mode: CleanupMode) -> trie::Result<()> { + pub fn add_balance(&mut self, a: &Address, incr: &U256, cleanup_mode: CleanupMode) -> TrieResult<()> { trace!(target: "state", "add_balance({}, {}): {}", a, incr, self.balance(a)?); let is_value_transfer = !incr.is_zero(); if is_value_transfer || (cleanup_mode == CleanupMode::ForceCreate && !self.exists(a)?) { @@ -635,7 +635,7 @@ impl State { } /// Subtract `decr` from the balance of account `a`. - pub fn sub_balance(&mut self, a: &Address, decr: &U256, cleanup_mode: &mut CleanupMode) -> trie::Result<()> { + pub fn sub_balance(&mut self, a: &Address, decr: &U256, cleanup_mode: &mut CleanupMode) -> TrieResult<()> { trace!(target: "state", "sub_balance({}, {}): {}", a, decr, self.balance(a)?); if !decr.is_zero() || !self.exists(a)? { self.require(a, false)?.sub_balance(decr); @@ -647,19 +647,19 @@ impl State { } /// Subtracts `by` from the balance of `from` and adds it to that of `to`. - pub fn transfer_balance(&mut self, from: &Address, to: &Address, by: &U256, mut cleanup_mode: CleanupMode) -> trie::Result<()> { + pub fn transfer_balance(&mut self, from: &Address, to: &Address, by: &U256, mut cleanup_mode: CleanupMode) -> TrieResult<()> { self.sub_balance(from, by, &mut cleanup_mode)?; self.add_balance(to, by, cleanup_mode)?; Ok(()) } /// Increment the nonce of account `a` by 1. - pub fn inc_nonce(&mut self, a: &Address) -> trie::Result<()> { + pub fn inc_nonce(&mut self, a: &Address) -> TrieResult<()> { self.require(a, false).map(|mut x| x.inc_nonce()) } /// Mutate storage of account `a` so that it is `value` for `key`. - pub fn set_storage(&mut self, a: &Address, key: H256, value: H256) -> trie::Result<()> { + pub fn set_storage(&mut self, a: &Address, key: H256, value: H256) -> TrieResult<()> { trace!(target: "state", "set_storage({}:{:x} to {:x})", a, key, value); if self.storage_at(a, &key)? != value { self.require(a, false)?.set_storage(key, value) @@ -670,13 +670,13 @@ impl State { /// Initialise the code of account `a` so that it is `code`. /// NOTE: Account should have been created with `new_contract`. - pub fn init_code(&mut self, a: &Address, code: Bytes) -> trie::Result<()> { + pub fn init_code(&mut self, a: &Address, code: Bytes) -> TrieResult<()> { self.require_or_from(a, true, || Account::new_contract(0.into(), self.account_start_nonce), |_|{})?.init_code(code); Ok(()) } /// Reset the code of account `a` so that it is `code`. - pub fn reset_code(&mut self, a: &Address, code: Bytes) -> trie::Result<()> { + pub fn reset_code(&mut self, a: &Address, code: Bytes) -> TrieResult<()> { self.require_or_from(a, true, || Account::new_contract(0.into(), self.account_start_nonce), |_|{})?.reset_code(code); Ok(()) } @@ -753,7 +753,7 @@ impl State { } } - fn touch(&mut self, a: &Address) -> trie::Result<()> { + fn touch(&mut self, a: &Address) -> TrieResult<()> { self.require(a, false)?; Ok(()) } @@ -809,7 +809,7 @@ impl State { } /// Remove any touched empty or dust accounts. - pub fn kill_garbage(&mut self, touched: &HashSet
, remove_empty_touched: bool, min_balance: &Option, kill_contracts: bool) -> trie::Result<()> { + pub fn kill_garbage(&mut self, touched: &HashSet
, remove_empty_touched: bool, min_balance: &Option, kill_contracts: bool) -> TrieResult<()> { let to_kill: HashSet<_> = { self.cache.borrow().iter().filter_map(|(address, ref entry)| if touched.contains(address) && // Check all touched accounts @@ -850,7 +850,7 @@ impl State { } /// Populate a PodAccount map from this state, with another state as the account and storage query. - pub fn to_pod_diff(&mut self, query: &State) -> trie::Result { + pub fn to_pod_diff(&mut self, query: &State) -> TrieResult { assert!(self.checkpoints.borrow().is_empty()); // Merge PodAccount::to_pod for cache of self and `query`. @@ -858,7 +858,7 @@ impl State { .chain(query.cache.borrow().keys().cloned()) .collect::>(); - Ok(PodState::from(all_addresses.into_iter().fold(Ok(BTreeMap::new()), |m: trie::Result<_>, address| { + Ok(PodState::from(all_addresses.into_iter().fold(Ok(BTreeMap::new()), |m: TrieResult<_>, address| { let mut m = m?; let account = self.ensure_cached(&address, RequireCache::Code, true, |acc| { @@ -886,7 +886,7 @@ impl State { })?; if let Some((balance, nonce, storage_keys, code)) = account { - let storage = storage_keys.into_iter().fold(Ok(BTreeMap::new()), |s: trie::Result<_>, key| { + let storage = storage_keys.into_iter().fold(Ok(BTreeMap::new()), |s: TrieResult<_>, key| { let mut s = s?; s.insert(key, self.storage_at(&address, &key)?); @@ -904,14 +904,14 @@ impl State { /// Returns a `StateDiff` describing the difference from `orig` to `self`. /// Consumes self. - pub fn diff_from(&self, mut orig: State) -> trie::Result { + pub fn diff_from(&self, mut orig: State) -> TrieResult { let pod_state_post = self.to_pod(); 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. - fn update_account_cache(require: RequireCache, account: &mut Account, state_db: &B, db: &HashDB) { + fn update_account_cache(require: RequireCache, account: &mut Account, state_db: &B, db: &HashDB) { if let RequireCache::None = require { return; } @@ -943,7 +943,7 @@ impl State { /// Check caches for required data /// First searches for account in the local, then the shared cache. /// Populates local cache if nothing found. - fn ensure_cached(&self, a: &Address, require: RequireCache, check_null: bool, f: F) -> trie::Result + fn ensure_cached(&self, a: &Address, require: RequireCache, check_null: bool, f: F) -> TrieResult where F: Fn(Option<&Account>) -> U { // check local cache first if let Some(ref mut maybe_acc) = self.cache.borrow_mut().get_mut(a) { @@ -984,13 +984,13 @@ impl State { } /// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too. - fn require<'a>(&'a self, a: &Address, require_code: bool) -> trie::Result> { + fn require<'a>(&'a self, a: &Address, require_code: bool) -> TrieResult> { self.require_or_from(a, require_code, || Account::new_basic(0u8.into(), self.account_start_nonce), |_|{}) } /// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too. /// If it doesn't exist, make account equal the evaluation of `default`. - fn require_or_from<'a, F, G>(&'a self, a: &Address, require_code: bool, default: F, not_default: G) -> trie::Result> + fn require_or_from<'a, F, G>(&'a self, a: &Address, require_code: bool, default: F, not_default: G) -> TrieResult> where F: FnOnce() -> Account, G: FnOnce(&mut Account), { let contains_key = self.cache.borrow().contains_key(a); @@ -1037,7 +1037,7 @@ impl State { } /// Replace account code and storage. Creates account if it does not exist. - pub fn patch_account(&self, a: &Address, code: Arc, storage: HashMap) -> trie::Result<()> { + pub fn patch_account(&self, a: &Address, code: Arc, storage: HashMap) -> TrieResult<()> { Ok(self.require(a, false)?.reset_code_and_storage(code, storage)) } } @@ -1049,7 +1049,7 @@ impl State { /// If the account doesn't exist in the trie, prove that and return defaults. /// Requires a secure trie to be used for accurate results. /// `account_key` == keccak(address) - pub fn prove_account(&self, account_key: H256) -> trie::Result<(Vec, BasicAccount)> { + pub fn prove_account(&self, account_key: H256) -> TrieResult<(Vec, BasicAccount)> { let mut recorder = Recorder::new(); let trie = TrieDB::new(self.db.as_hashdb(), &self.root)?; let maybe_account: Option = { @@ -1074,7 +1074,7 @@ impl State { /// Requires a secure trie to be used for correctness. /// `account_key` == keccak(address) /// `storage_key` == keccak(key) - pub fn prove_storage(&self, account_key: H256, storage_key: H256) -> trie::Result<(Vec, H256)> { + pub fn prove_storage(&self, account_key: H256, storage_key: H256) -> TrieResult<(Vec, H256)> { // TODO: probably could look into cache somehow but it's keyed by // address, not keccak(address). let trie = TrieDB::new(self.db.as_hashdb(), &self.root)?; diff --git a/ethcore/src/state_db.rs b/ethcore/src/state_db.rs index c3704828c25..d614fe42f84 100644 --- a/ethcore/src/state_db.rs +++ b/ethcore/src/state_db.rs @@ -17,21 +17,23 @@ //! State database abstraction. For more info, see the doc for `StateDB` use std::collections::{VecDeque, HashSet}; +use std::io; use std::sync::Arc; -use lru_cache::LruCache; -use memory_cache::MemoryLruCache; -use journaldb::JournalDB; -use kvdb::{KeyValueDB, DBTransaction}; + +use bloom_journal::{Bloom, BloomJournal}; +use byteorder::{LittleEndian, ByteOrder}; +use db::COL_ACCOUNT_BLOOM; use ethereum_types::{H256, Address}; +use hash::keccak; use hashdb::HashDB; -use state::{self, Account}; +use keccak_hasher::KeccakHasher; use header::BlockNumber; -use hash::keccak; +use journaldb::JournalDB; +use kvdb::{KeyValueDB, DBTransaction}; +use lru_cache::LruCache; +use memory_cache::MemoryLruCache; use parking_lot::Mutex; -use util_error::UtilError; -use bloom_journal::{Bloom, BloomJournal}; -use db::COL_ACCOUNT_BLOOM; -use byteorder::{LittleEndian, ByteOrder}; +use state::{self, Account}; /// Value used to initialize bloom bitmap size. /// @@ -180,7 +182,7 @@ impl StateDB { } /// Commit blooms journal to the database transaction - pub fn commit_bloom(batch: &mut DBTransaction, journal: BloomJournal) -> Result<(), UtilError> { + pub fn commit_bloom(batch: &mut DBTransaction, journal: BloomJournal) -> io::Result<()> { assert!(journal.hash_functions <= 255); batch.put(COL_ACCOUNT_BLOOM, ACCOUNT_BLOOM_HASHCOUNT_KEY, &[journal.hash_functions as u8]); let mut key = [0u8; 8]; @@ -195,7 +197,7 @@ impl StateDB { } /// Journal all recent operations under the given era and ID. - pub fn journal_under(&mut self, batch: &mut DBTransaction, now: u64, id: &H256) -> Result { + pub fn journal_under(&mut self, batch: &mut DBTransaction, now: u64, id: &H256) -> io::Result { { let mut bloom_lock = self.account_bloom.lock(); Self::commit_bloom(batch, bloom_lock.drain_journal())?; @@ -208,7 +210,7 @@ impl StateDB { /// Mark a given candidate from an ancient era as canonical, enacting its removals from the /// backing database and reverting any non-canonical historical commit's insertions. - pub fn mark_canonical(&mut self, batch: &mut DBTransaction, end_era: u64, canon_id: &H256) -> Result { + pub fn mark_canonical(&mut self, batch: &mut DBTransaction, end_era: u64, canon_id: &H256) -> io::Result { self.db.mark_canonical(batch, end_era, canon_id) } @@ -310,12 +312,12 @@ impl StateDB { } /// Conversion method to interpret self as `HashDB` reference - pub fn as_hashdb(&self) -> &HashDB { + pub fn as_hashdb(&self) -> &HashDB { self.db.as_hashdb() } /// Conversion method to interpret self as mutable `HashDB` reference - pub fn as_hashdb_mut(&mut self) -> &mut HashDB { + pub fn as_hashdb_mut(&mut self) -> &mut HashDB { self.db.as_hashdb_mut() } @@ -410,11 +412,9 @@ impl StateDB { } impl state::Backend for StateDB { - fn as_hashdb(&self) -> &HashDB { - self.db.as_hashdb() - } + fn as_hashdb(&self) -> &HashDB { self.db.as_hashdb() } - fn as_hashdb_mut(&mut self) -> &mut HashDB { + fn as_hashdb_mut(&mut self) -> &mut HashDB { self.db.as_hashdb_mut() } diff --git a/ethcore/src/verification/mod.rs b/ethcore/src/verification/mod.rs index ed4227ee21e..56cb2ade773 100644 --- a/ethcore/src/verification/mod.rs +++ b/ethcore/src/verification/mod.rs @@ -42,12 +42,6 @@ pub enum VerifierType { Noop, } -impl Default for VerifierType { - fn default() -> Self { - VerifierType::Canon - } -} - /// Create a new verifier based on type. pub fn new(v: VerifierType) -> Box> { match v { diff --git a/ethcore/stratum/Cargo.toml b/ethcore/stratum/Cargo.toml index bf967df504a..e160907a499 100644 --- a/ethcore/stratum/Cargo.toml +++ b/ethcore/stratum/Cargo.toml @@ -12,7 +12,7 @@ jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "pa jsonrpc-macros = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } jsonrpc-tcp-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } log = "0.3" -parking_lot = "0.5" +parking_lot = "0.6" [dev-dependencies] env_logger = "0.4" diff --git a/ethcore/sync/Cargo.toml b/ethcore/sync/Cargo.toml index 66ee5662158..1e539bc4a1b 100644 --- a/ethcore/sync/Cargo.toml +++ b/ethcore/sync/Cargo.toml @@ -16,10 +16,12 @@ ethcore-light = { path = "../light" } ethcore-transaction = { path = "../transaction" } ethcore = { path = ".." } ethereum-types = "0.3" -plain_hasher = { path = "../../util/plain_hasher" } +hashdb = { version = "0.2", path = "../../util/hashdb" } +plain_hasher = { version = "0.2", path = "../../util/plain_hasher" } rlp = { path = "../../util/rlp" } rustc-hex = "1.0" keccak-hash = { path = "../../util/hash" } +keccak-hasher = { path = "../../util/keccak-hasher" } triehash = { path = "../../util/triehash" } kvdb = { path = "../../util/kvdb" } macros = { path = "../../util/macros" } @@ -29,7 +31,7 @@ rand = "0.4" heapsize = "0.4" semver = "0.9" smallvec = { version = "0.4", features = ["heapsizeof"] } -parking_lot = "0.5" +parking_lot = "0.6" trace-time = { path = "../../util/trace-time" } ipnetwork = "0.12.6" diff --git a/ethcore/sync/src/api.rs b/ethcore/sync/src/api.rs index 56bc579ad88..ef54a4802d9 100644 --- a/ethcore/sync/src/api.rs +++ b/ethcore/sync/src/api.rs @@ -384,7 +384,6 @@ impl NetworkProtocolHandler for SyncProtocolHandler { } fn read(&self, io: &NetworkContext, peer: &PeerId, packet_id: u8, data: &[u8]) { - trace_time!("sync::read"); ChainSync::dispatch_packet(&self.sync, &mut NetSyncIo::new(io, &*self.chain, &*self.snapshot_service, &self.overlay), *peer, packet_id, data); } diff --git a/ethcore/sync/src/chain/mod.rs b/ethcore/sync/src/chain/mod.rs index 84e6344e688..50f4c9428a1 100644 --- a/ethcore/sync/src/chain/mod.rs +++ b/ethcore/sync/src/chain/mod.rs @@ -662,20 +662,29 @@ impl ChainSync { None } ).collect(); - let mut peers: Vec<(PeerId, u8)> = confirmed_peers.iter().filter(|&&(peer_id, _)| - self.active_peers.contains(&peer_id) - ).map(|v| *v).collect(); - random::new().shuffle(&mut peers); //TODO: sort by rating - // prefer peers with higher protocol version - peers.sort_by(|&(_, ref v1), &(_, ref v2)| v1.cmp(v2)); trace!( target: "sync", "Syncing with peers: {} active, {} confirmed, {} total", self.active_peers.len(), confirmed_peers.len(), self.peers.len() ); - for (peer_id, _) in peers { - self.sync_peer(io, peer_id, false); + + if self.state == SyncState::Waiting { + trace!(target: "sync", "Waiting for the block queue"); + } else if self.state == SyncState::SnapshotWaiting { + trace!(target: "sync", "Waiting for the snapshot restoration"); + } else { + let mut peers: Vec<(PeerId, u8)> = confirmed_peers.iter().filter(|&&(peer_id, _)| + self.active_peers.contains(&peer_id) + ).map(|v| *v).collect(); + + random::new().shuffle(&mut peers); //TODO: sort by rating + // prefer peers with higher protocol version + peers.sort_by(|&(_, ref v1), &(_, ref v2)| v1.cmp(v2)); + + for (peer_id, _) in peers { + self.sync_peer(io, peer_id, false); + } } if @@ -710,14 +719,6 @@ impl ChainSync { trace!(target: "sync", "Skipping busy peer {}", peer_id); return; } - if self.state == SyncState::Waiting { - trace!(target: "sync", "Waiting for the block queue"); - return; - } - if self.state == SyncState::SnapshotWaiting { - trace!(target: "sync", "Waiting for the snapshot restoration"); - return; - } (peer.latest_hash.clone(), peer.difficulty.clone(), peer.snapshot_number.as_ref().cloned().unwrap_or(0), peer.snapshot_hash.as_ref().cloned()) } else { return; diff --git a/ethcore/sync/src/chain/supplier.rs b/ethcore/sync/src/chain/supplier.rs index 9b6efbacbb7..e8a5c93ea3d 100644 --- a/ethcore/sync/src/chain/supplier.rs +++ b/ethcore/sync/src/chain/supplier.rs @@ -22,6 +22,7 @@ use network::{self, PeerId}; use parking_lot::RwLock; use rlp::{Rlp, RlpStream}; use std::cmp; + use sync_io::SyncIo; use super::{ diff --git a/ethcore/sync/src/lib.rs b/ethcore/sync/src/lib.rs index 35483f4ec3a..6e49b1ce78d 100644 --- a/ethcore/sync/src/lib.rs +++ b/ethcore/sync/src/lib.rs @@ -30,6 +30,7 @@ extern crate ethcore_transaction as transaction; extern crate ethcore; extern crate ethereum_types; extern crate env_logger; +extern crate hashdb; extern crate plain_hasher; extern crate rand; extern crate semver; @@ -38,6 +39,7 @@ extern crate smallvec; extern crate rlp; extern crate ipnetwork; extern crate keccak_hash as hash; +extern crate keccak_hasher; extern crate triehash; extern crate kvdb; diff --git a/ethcore/types/src/account_diff.rs b/ethcore/types/src/account_diff.rs index 521ed8ab1f8..9633ffeb078 100644 --- a/ethcore/types/src/account_diff.rs +++ b/ethcore/types/src/account_diff.rs @@ -24,7 +24,7 @@ use bytes::Bytes; #[derive(Debug, PartialEq, Eq, Clone)] /// Diff type for specifying a change (or not). -pub enum Diff where T: Eq { +pub enum Diff { /// Both sides are the same. Same, /// Left (pre, source) side doesn't include value, right side (post, destination) does. @@ -35,9 +35,15 @@ pub enum Diff where T: Eq { Died(T), } -impl Diff where T: Eq { +impl Diff { /// Construct new object with given `pre` and `post`. - pub fn new(pre: T, post: T) -> Self { if pre == post { Diff::Same } else { Diff::Changed(pre, post) } } + pub fn new(pre: T, post: T) -> Self where T: Eq { + if pre == post { + Diff::Same + } else { + Diff::Changed(pre, post) + } + } /// Get the before value, if there is one. pub fn pre(&self) -> Option<&T> { match *self { Diff::Died(ref x) | Diff::Changed(ref x, _) => Some(x), _ => None } } diff --git a/ethcore/vm/Cargo.toml b/ethcore/vm/Cargo.toml index c5d31f58e61..7348951d790 100644 --- a/ethcore/vm/Cargo.toml +++ b/ethcore/vm/Cargo.toml @@ -8,6 +8,7 @@ byteorder = "1.0" ethcore-bytes = { path = "../../util/bytes" } ethereum-types = "0.3" patricia-trie = { path = "../../util/patricia_trie" } +patricia-trie-ethereum = { path = "../../util/patricia-trie-ethereum" } log = "0.3" common-types = { path = "../types" } ethjson = { path = "../../json" } diff --git a/ethcore/vm/src/error.rs b/ethcore/vm/src/error.rs index ad23e3e020e..b5e337a75fb 100644 --- a/ethcore/vm/src/error.rs +++ b/ethcore/vm/src/error.rs @@ -16,8 +16,8 @@ //! VM errors module -use trie; use std::fmt; +use ethtrie; /// VM errors. #[derive(Debug, Clone, PartialEq)] @@ -71,8 +71,13 @@ pub enum Error { Reverted, } -impl From> for Error { - fn from(err: Box) -> Self { +impl From> for Error { + fn from(err: Box) -> Self { + Error::Internal(format!("Internal error: {}", err)) + } +} +impl From for Error { + fn from(err: ethtrie::TrieError) -> Self { Error::Internal(format!("Internal error: {}", err)) } } diff --git a/ethcore/vm/src/lib.rs b/ethcore/vm/src/lib.rs index 0dc1b799549..658420f74e3 100644 --- a/ethcore/vm/src/lib.rs +++ b/ethcore/vm/src/lib.rs @@ -22,6 +22,7 @@ extern crate common_types as types; extern crate ethjson; extern crate rlp; extern crate keccak_hash as hash; +extern crate patricia_trie_ethereum as ethtrie; extern crate patricia_trie as trie; mod action_params; diff --git a/ethcore/wasm/Cargo.toml b/ethcore/wasm/Cargo.toml index a0362955d1d..5ca2f31220a 100644 --- a/ethcore/wasm/Cargo.toml +++ b/ethcore/wasm/Cargo.toml @@ -7,9 +7,9 @@ authors = ["Parity Technologies "] byteorder = "1.0" ethereum-types = "0.3" log = "0.3" -parity-wasm = "0.27" +parity-wasm = "0.31" libc = "0.2" -pwasm-utils = "0.1" +pwasm-utils = "0.2.2" vm = { path = "../vm" } ethcore-logger = { path = "../../logger" } -wasmi = { version = "0.2" } +wasmi = "0.3.0" diff --git a/ethcore/wasm/src/parser.rs b/ethcore/wasm/src/parser.rs index 1efb89e1bdd..656ebb30191 100644 --- a/ethcore/wasm/src/parser.rs +++ b/ethcore/wasm/src/parser.rs @@ -25,7 +25,7 @@ fn gas_rules(wasm_costs: &vm::WasmCosts) -> rules::Set { rules::Set::new( wasm_costs.regular, { - let mut vals = ::std::collections::HashMap::with_capacity(8); + let mut vals = ::std::collections::BTreeMap::new(); vals.insert(rules::InstructionType::Load, rules::Metering::Fixed(wasm_costs.mem as u32)); vals.insert(rules::InstructionType::Store, rules::Metering::Fixed(wasm_costs.mem as u32)); vals.insert(rules::InstructionType::Div, rules::Metering::Fixed(wasm_costs.div as u32)); diff --git a/ethcore/wasm/src/tests.rs b/ethcore/wasm/src/tests.rs index b32ca75ae96..726b9ebabbb 100644 --- a/ethcore/wasm/src/tests.rs +++ b/ethcore/wasm/src/tests.rs @@ -86,7 +86,7 @@ fn empty() { test_finalize(interpreter.exec(params, &mut ext)).unwrap() }; - assert_eq!(gas_left, U256::from(98462)); + assert_eq!(gas_left, U256::from(96_926)); } // This test checks if the contract deserializes payload header properly. @@ -138,7 +138,7 @@ fn logger() { U256::from(1_000_000_000), "Logger sets 0x04 key to the trasferred value" ); - assert_eq!(gas_left, U256::from(17_578)); + assert_eq!(gas_left, U256::from(16_181)); } // This test checks if the contract can allocate memory and pass pointer to the result stream properly. @@ -173,7 +173,7 @@ fn identity() { sender, "Idenity test contract does not return the sender passed" ); - assert_eq!(gas_left, U256::from(98_408)); + assert_eq!(gas_left, U256::from(96_883)); } // Dispersion test sends byte array and expect the contract to 'disperse' the original elements with @@ -207,7 +207,7 @@ fn dispersion() { result, vec![0u8, 0, 125, 11, 197, 7, 255, 8, 19, 0] ); - assert_eq!(gas_left, U256::from(94_013)); + assert_eq!(gas_left, U256::from(92_371)); } #[test] @@ -235,7 +235,7 @@ fn suicide_not() { result, vec![0u8] ); - assert_eq!(gas_left, U256::from(94_984)); + assert_eq!(gas_left, U256::from(93_378)); } #[test] @@ -267,7 +267,7 @@ fn suicide() { }; assert!(ext.suicides.contains(&refund)); - assert_eq!(gas_left, U256::from(94_925)); + assert_eq!(gas_left, U256::from(93_348)); } #[test] @@ -297,7 +297,7 @@ fn create() { assert!(ext.calls.contains( &FakeCall { call_type: FakeCallType::Create, - gas: U256::from(60_914), + gas: U256::from(59_269), sender_address: None, receive_address: None, value: Some(1_000_000_000.into()), @@ -305,7 +305,7 @@ fn create() { code_address: None, } )); - assert_eq!(gas_left, U256::from(60_900)); + assert_eq!(gas_left, U256::from(59_212)); } #[test] @@ -349,7 +349,7 @@ fn call_msg() { } )); - assert_eq!(gas_left, U256::from(93_511)); + assert_eq!(gas_left, U256::from(91_672)); } #[test] @@ -394,7 +394,7 @@ fn call_code() { // siphash result let res = LittleEndian::read_u32(&result[..]); assert_eq!(res, 4198595614); - assert_eq!(gas_left, U256::from(92_381)); + assert_eq!(gas_left, U256::from(90_038)); } #[test] @@ -442,7 +442,7 @@ fn call_static() { let res = LittleEndian::read_u32(&result[..]); assert_eq!(res, 317632590); - assert_eq!(gas_left, U256::from(92_381)); + assert_eq!(gas_left, U256::from(90_043)); } // Realloc test @@ -465,7 +465,7 @@ fn realloc() { } }; assert_eq!(result, vec![0u8; 2]); - assert_eq!(gas_left, U256::from(94_372)); + assert_eq!(gas_left, U256::from(92_842)); } #[test] @@ -486,8 +486,8 @@ fn alloc() { GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()), } }; - assert_eq!(result, vec![5u8; 1024*450]); - assert_eq!(gas_left, U256::from(6_506_844)); + assert_eq!(result, vec![5u8; 1024*400]); + assert_eq!(gas_left, U256::from(6_893_883)); } // Tests that contract's ability to read from a storage @@ -515,7 +515,7 @@ fn storage_read() { }; assert_eq!(Address::from(&result[12..32]), address); - assert_eq!(gas_left, U256::from(98_298)); + assert_eq!(gas_left, U256::from(96_833)); } // Tests keccak calculation @@ -541,7 +541,7 @@ fn keccak() { }; assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87")); - assert_eq!(gas_left, U256::from(84_240)); + assert_eq!(gas_left, U256::from(84_134)); } // math_* tests check the ability of wasm contract to perform big integer operations @@ -570,7 +570,7 @@ fn math_add() { U256::from_dec_str("1888888888888888888888888888887").unwrap(), (&result[..]).into() ); - assert_eq!(gas_left, U256::from(93_814)); + assert_eq!(gas_left, U256::from(92_086)); } // multiplication @@ -592,7 +592,7 @@ fn math_mul() { U256::from_dec_str("888888888888888888888888888887111111111111111111111111111112").unwrap(), (&result[..]).into() ); - assert_eq!(gas_left, U256::from(93_300)); + assert_eq!(gas_left, U256::from(91_414)); } // subtraction @@ -614,7 +614,7 @@ fn math_sub() { U256::from_dec_str("111111111111111111111111111111").unwrap(), (&result[..]).into() ); - assert_eq!(gas_left, U256::from(93_826)); + assert_eq!(gas_left, U256::from(92_086)); } // subtraction with overflow @@ -656,7 +656,7 @@ fn math_div() { U256::from_dec_str("1125000").unwrap(), (&result[..]).into() ); - assert_eq!(gas_left, U256::from(90_603)); + assert_eq!(gas_left, U256::from(87_376)); } #[test] @@ -684,7 +684,7 @@ fn storage_metering() { }; // 0 -> not 0 - assert_eq!(gas_left, U256::from(74_338)); + assert_eq!(gas_left, U256::from(72_399)); // #2 @@ -703,7 +703,7 @@ fn storage_metering() { }; // not 0 -> not 0 - assert_eq!(gas_left, U256::from(89_338)); + assert_eq!(gas_left, U256::from(87_399)); } // This test checks the ability of wasm contract to invoke @@ -791,7 +791,7 @@ fn externs() { "Gas limit requested and returned does not match" ); - assert_eq!(gas_left, U256::from(92_110)); + assert_eq!(gas_left, U256::from(90_435)); } #[test] @@ -817,7 +817,7 @@ fn embedded_keccak() { }; assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87")); - assert_eq!(gas_left, U256::from(84_240)); + assert_eq!(gas_left, U256::from(84_134)); } /// This test checks the correctness of log extern @@ -852,5 +852,45 @@ fn events() { assert_eq!(&log_entry.data, b"gnihtemos"); assert_eq!(&result, b"gnihtemos"); - assert_eq!(gas_left, U256::from(81_292)); + assert_eq!(gas_left, U256::from(81_351)); +} + +#[test] +fn recursive() { + ::ethcore_logger::init_log(); + let code = load_sample!("recursive.wasm"); + + let mut params = ActionParams::default(); + params.gas = U256::from(100_000_000); + params.code = Some(Arc::new(code)); + params.data = Some({ + // `recursive` expects only one 32-bit word in LE that + // represents an iteration count. + // + // We pick a relative big number to definitely hit stack overflow. + use byteorder::WriteBytesExt; + let mut data = vec![]; + data.write_u32::(100000).unwrap(); + data + }); + + let mut ext = FakeExt::new().with_wasm(); + + let mut interpreter = wasm_interpreter(); + let result = interpreter.exec(params, &mut ext); + + // We expect that stack overflow will occur and it should be generated by + // deterministic stack metering. Exceeding deterministic stack height limit + // always ends with a trap generated by `unreachable` instruction. + match result { + Err(trap) => { + let err_description = trap.to_string(); + assert!( + err_description.contains("Unreachable"), + "err_description: {} should contain 'Unreachable'", + err_description + ); + }, + _ => panic!("this test should trap"), + } } diff --git a/ethstore/Cargo.toml b/ethstore/Cargo.toml index 6108143cb9e..038b27fbe62 100644 --- a/ethstore/Cargo.toml +++ b/ethstore/Cargo.toml @@ -15,7 +15,7 @@ rustc-hex = "1.0" tiny-keccak = "1.4" time = "0.1.34" itertools = "0.5" -parking_lot = "0.5" +parking_lot = "0.6" ethcore-crypto = { path = "../ethcore/crypto" } ethereum-types = "0.3" dir = { path = "../util/dir" } diff --git a/ethstore/cli/Cargo.toml b/ethstore/cli/Cargo.toml index bd5db86216f..b1736efdb38 100644 --- a/ethstore/cli/Cargo.toml +++ b/ethstore/cli/Cargo.toml @@ -9,7 +9,7 @@ num_cpus = "1.6" rustc-hex = "1.0" serde = "1.0" serde_derive = "1.0" -parking_lot = "0.5" +parking_lot = "0.6" ethstore = { path = "../" } dir = { path = '../../util/dir' } panic_hook = { path = "../../util/panic_hook" } diff --git a/hash-fetch/Cargo.toml b/hash-fetch/Cargo.toml index d4f46a121e8..df332602c04 100644 --- a/hash-fetch/Cargo.toml +++ b/hash-fetch/Cargo.toml @@ -27,5 +27,5 @@ ethabi-contract = "5.0" [dev-dependencies] hyper = "0.11" -parking_lot = "0.5" +parking_lot = "0.6" fake-fetch = { path = "../util/fake-fetch" } diff --git a/hw/Cargo.toml b/hw/Cargo.toml index dd4adcefd5c..b7d90648eac 100644 --- a/hw/Cargo.toml +++ b/hw/Cargo.toml @@ -8,7 +8,7 @@ authors = ["Parity Technologies "] [dependencies] log = "0.3" -parking_lot = "0.5" +parking_lot = "0.6" protobuf = "1.4" hidapi = { git = "https://github.com/paritytech/hidapi-rs" } libusb = { git = "https://github.com/paritytech/libusb-rs" } diff --git a/logger/Cargo.toml b/logger/Cargo.toml index a1f793769c5..3db404bf645 100644 --- a/logger/Cargo.toml +++ b/logger/Cargo.toml @@ -12,6 +12,6 @@ atty = "0.2" lazy_static = "1.0" regex = "0.2" time = "0.1" -parking_lot = "0.5" +parking_lot = "0.6" arrayvec = "0.4" ansi_term = "0.10" diff --git a/logger/src/lib.rs b/logger/src/lib.rs index 2a509698028..6918397886d 100644 --- a/logger/src/lib.rs +++ b/logger/src/lib.rs @@ -71,7 +71,7 @@ pub fn setup_log(config: &Config) -> Result, String> { builder.filter(Some("ws"), LogLevelFilter::Warn); builder.filter(Some("reqwest"), LogLevelFilter::Warn); builder.filter(Some("hyper"), LogLevelFilter::Warn); - builder.filter(Some("rustls"), LogLevelFilter::Warn); + builder.filter(Some("rustls"), LogLevelFilter::Error); // Enable info for others. builder.filter(None, LogLevelFilter::Info); diff --git a/miner/Cargo.toml b/miner/Cargo.toml index 53771e5c16e..e1e7974a6a7 100644 --- a/miner/Cargo.toml +++ b/miner/Cargo.toml @@ -8,11 +8,11 @@ authors = ["Parity Technologies "] [dependencies] # Only work_notify, consider a separate crate -ethash = { path = "../ethash" } -fetch = { path = "../util/fetch" } -hyper = "0.11" -parity-reactor = { path = "../util/reactor" } -url = "1" +ethash = { path = "../ethash", optional = true } +fetch = { path = "../util/fetch", optional = true } +hyper = { version = "0.11", optional = true } +parity-reactor = { path = "../util/reactor", optional = true } +url = { version = "1", optional = true } # Miner ansi_term = "0.10" @@ -25,8 +25,8 @@ heapsize = "0.4" keccak-hash = { path = "../util/hash" } linked-hash-map = "0.5" log = "0.3" -parking_lot = "0.5" -price-info = { path = "../price-info" } +parking_lot = "0.6" +price-info = { path = "../price-info", optional = true } rlp = { path = "../util/rlp" } trace-time = { path = "../util/trace-time" } transaction-pool = { path = "../transaction-pool" } @@ -35,3 +35,6 @@ transaction-pool = { path = "../transaction-pool" } env_logger = "0.4" ethkey = { path = "../ethkey" } rustc-hex = "1.0" + +[features] +work-notify = ["ethash", "fetch", "hyper", "parity-reactor", "url"] diff --git a/miner/src/gas_price_calibrator.rs b/miner/src/gas_price_calibrator.rs new file mode 100644 index 00000000000..d2978220a6a --- /dev/null +++ b/miner/src/gas_price_calibrator.rs @@ -0,0 +1,73 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Auto-updates minimal gas price requirement from a price-info source. + +use std::time::{Instant, Duration}; + +use ansi_term::Colour; +use ethereum_types::U256; +use futures_cpupool::CpuPool; +use price_info::{Client as PriceInfoClient, PriceInfo}; +use price_info::fetch::Client as FetchClient; + +/// Options for the dynamic gas price recalibrator. +#[derive(Debug, PartialEq)] +pub struct GasPriceCalibratorOptions { + /// Base transaction price to match against. + pub usd_per_tx: f32, + /// How frequently we should recalibrate. + pub recalibration_period: Duration, +} + +/// The gas price validator variant for a `GasPricer`. +#[derive(Debug, PartialEq)] +pub struct GasPriceCalibrator { + options: GasPriceCalibratorOptions, + next_calibration: Instant, + price_info: PriceInfoClient, +} + +impl GasPriceCalibrator { + /// Create a new gas price calibrator. + pub fn new(options: GasPriceCalibratorOptions, fetch: FetchClient, p: CpuPool) -> GasPriceCalibrator { + GasPriceCalibrator { + options: options, + next_calibration: Instant::now(), + price_info: PriceInfoClient::new(fetch, p), + } + } + + pub(crate) fn recalibrate(&mut self, set_price: F) { + trace!(target: "miner", "Recalibrating {:?} versus {:?}", Instant::now(), self.next_calibration); + if Instant::now() >= self.next_calibration { + let usd_per_tx = self.options.usd_per_tx; + trace!(target: "miner", "Getting price info"); + + self.price_info.get(move |price: PriceInfo| { + trace!(target: "miner", "Price info arrived: {:?}", price); + let usd_per_eth = price.ethusd; + let wei_per_usd: f32 = 1.0e18 / usd_per_eth; + let gas_per_tx: f32 = 21000.0; + let wei_per_gas: f32 = wei_per_usd * usd_per_tx / gas_per_tx; + info!(target: "miner", "Updated conversion rate to Ξ1 = {} ({} wei/gas)", Colour::White.bold().paint(format!("US${:.2}", usd_per_eth)), Colour::Yellow.bold().paint(format!("{}", wei_per_gas))); + set_price(U256::from(wei_per_gas as u64)); + }); + + self.next_calibration = Instant::now() + self.options.recalibration_period; + } + } +} diff --git a/miner/src/gas_pricer.rs b/miner/src/gas_pricer.rs index ecb69ba572e..32877836529 100644 --- a/miner/src/gas_pricer.rs +++ b/miner/src/gas_pricer.rs @@ -16,52 +16,9 @@ //! Auto-updates minimal gas price requirement. -use std::time::{Instant, Duration}; - -use ansi_term::Colour; use ethereum_types::U256; -use futures_cpupool::CpuPool; -use price_info::{Client as PriceInfoClient, PriceInfo}; -use price_info::fetch::Client as FetchClient; - -/// Options for the dynamic gas price recalibrator. -#[derive(Debug, PartialEq)] -pub struct GasPriceCalibratorOptions { - /// Base transaction price to match against. - pub usd_per_tx: f32, - /// How frequently we should recalibrate. - pub recalibration_period: Duration, -} - -/// The gas price validator variant for a `GasPricer`. -#[derive(Debug, PartialEq)] -pub struct GasPriceCalibrator { - options: GasPriceCalibratorOptions, - next_calibration: Instant, - price_info: PriceInfoClient, -} - -impl GasPriceCalibrator { - fn recalibrate(&mut self, set_price: F) { - trace!(target: "miner", "Recalibrating {:?} versus {:?}", Instant::now(), self.next_calibration); - if Instant::now() >= self.next_calibration { - let usd_per_tx = self.options.usd_per_tx; - trace!(target: "miner", "Getting price info"); - - self.price_info.get(move |price: PriceInfo| { - trace!(target: "miner", "Price info arrived: {:?}", price); - let usd_per_eth = price.ethusd; - let wei_per_usd: f32 = 1.0e18 / usd_per_eth; - let gas_per_tx: f32 = 21000.0; - let wei_per_gas: f32 = wei_per_usd * usd_per_tx / gas_per_tx; - info!(target: "miner", "Updated conversion rate to Ξ1 = {} ({} wei/gas)", Colour::White.bold().paint(format!("US${:.2}", usd_per_eth)), Colour::Yellow.bold().paint(format!("{}", wei_per_gas))); - set_price(U256::from(wei_per_gas as u64)); - }); - - self.next_calibration = Instant::now() + self.options.recalibration_period; - } - } -} +#[cfg(feature = "price-info")] +use gas_price_calibrator::GasPriceCalibrator; /// Struct to look after updating the acceptable gas price of a miner. #[derive(Debug, PartialEq)] @@ -69,17 +26,15 @@ pub enum GasPricer { /// A fixed gas price in terms of Wei - always the argument given. Fixed(U256), /// Gas price is calibrated according to a fixed amount of USD. + #[cfg(feature = "price-info")] Calibrated(GasPriceCalibrator), } impl GasPricer { /// Create a new Calibrated `GasPricer`. - pub fn new_calibrated(options: GasPriceCalibratorOptions, fetch: FetchClient, p: CpuPool) -> GasPricer { - GasPricer::Calibrated(GasPriceCalibrator { - options: options, - next_calibration: Instant::now(), - price_info: PriceInfoClient::new(fetch, p), - }) + #[cfg(feature = "price-info")] + pub fn new_calibrated(calibrator: GasPriceCalibrator) -> GasPricer { + GasPricer::Calibrated(calibrator) } /// Create a new Fixed `GasPricer`. @@ -91,6 +46,7 @@ impl GasPricer { pub fn recalibrate(&mut self, set_price: F) { match *self { GasPricer::Fixed(ref max) => set_price(max.clone()), + #[cfg(feature = "price-info")] GasPricer::Calibrated(ref mut cal) => cal.recalibrate(set_price), } } diff --git a/miner/src/lib.rs b/miner/src/lib.rs index 6b61df4de4e..e1ae0a9e05c 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -28,6 +28,7 @@ extern crate heapsize; extern crate keccak_hash as hash; extern crate linked_hash_map; extern crate parking_lot; +#[cfg(feature = "price-info")] extern crate price_info; extern crate rlp; extern crate transaction_pool as txpool; @@ -47,6 +48,9 @@ extern crate ethkey; extern crate env_logger; pub mod external; +#[cfg(feature = "price-info")] +pub mod gas_price_calibrator; pub mod gas_pricer; pub mod pool; +#[cfg(feature = "work-notify")] pub mod work_notify; diff --git a/miner/src/pool/queue.rs b/miner/src/pool/queue.rs index 450075faa6e..24a56c226a1 100644 --- a/miner/src/pool/queue.rs +++ b/miner/src/pool/queue.rs @@ -19,7 +19,7 @@ use std::{cmp, fmt}; use std::sync::Arc; use std::sync::atomic::{self, AtomicUsize}; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, BTreeSet, HashMap}; use ethereum_types::{H256, U256, Address}; use parking_lot::RwLock; @@ -43,6 +43,14 @@ type Pool = txpool::Pool>, + limit: usize, +} + +impl RecentlyRejected { + fn new(limit: usize) -> Self { + RecentlyRejected { + limit, + inner: RwLock::new(HashMap::with_capacity(MIN_REJECTED_CACHE_SIZE)), + } + } + + fn clear(&self) { + self.inner.write().clear(); + } + + fn get(&self, hash: &H256) -> Option { + self.inner.read().get(hash).cloned() + } + + fn insert(&self, hash: H256, err: &transaction::Error) { + if self.inner.read().contains_key(&hash) { + return; + } + + let mut inner = self.inner.write(); + inner.insert(hash, err.clone()); + + // clean up + if inner.len() > self.limit { + // randomly remove half of the entries + let to_remove: Vec<_> = inner.keys().take(self.limit / 2).cloned().collect(); + for key in to_remove { + inner.remove(&key); + } + } + } +} + +/// Minimal size of rejection cache, by default it's equal to queue size. +const MIN_REJECTED_CACHE_SIZE: usize = 2048; + /// Ethereum Transaction Queue /// /// Responsible for: @@ -150,6 +202,7 @@ pub struct TransactionQueue { pool: RwLock, options: RwLock, cached_pending: RwLock, + recently_rejected: RecentlyRejected, } impl TransactionQueue { @@ -159,11 +212,13 @@ impl TransactionQueue { verification_options: verifier::Options, strategy: PrioritizationStrategy, ) -> Self { + let max_count = limits.max_count; TransactionQueue { insertion_id: Default::default(), pool: RwLock::new(txpool::Pool::new(Default::default(), scoring::NonceAndGasPrice(strategy), limits)), options: RwLock::new(verification_options), cached_pending: RwLock::new(CachedPending::none()), + recently_rejected: RecentlyRejected::new(cmp::max(MIN_REJECTED_CACHE_SIZE, max_count / 4)), } } @@ -195,26 +250,42 @@ impl TransactionQueue { None } }; + let verifier = verifier::Verifier::new( client, options, self.insertion_id.clone(), transaction_to_replace, ); + let results = transactions .into_iter() .map(|transaction| { - if self.pool.read().find(&transaction.hash()).is_some() { - bail!(transaction::Error::AlreadyImported) + let hash = transaction.hash(); + + if self.pool.read().find(&hash).is_some() { + return Err(transaction::Error::AlreadyImported); + } + + if let Some(err) = self.recently_rejected.get(&hash) { + trace!(target: "txqueue", "[{:?}] Rejecting recently rejected: {:?}", hash, err); + return Err(err); } - verifier.verify_transaction(transaction) + let imported = verifier + .verify_transaction(transaction) + .and_then(|verified| { + self.pool.write().import(verified).map_err(convert_error) + }); + + match imported { + Ok(_) => Ok(()), + Err(err) => { + self.recently_rejected.insert(hash, &err); + Err(err) + }, + } }) - .map(|result| result.and_then(|verified| { - self.pool.write().import(verified) - .map(|_imported| ()) - .map_err(convert_error) - })) .collect::>(); // Notify about imported transactions. @@ -233,6 +304,19 @@ impl TransactionQueue { self.pool.read().unordered_pending(ready).collect() } + /// Computes unordered set of pending hashes. + /// + /// Since strict nonce-checking is not required, you may get some false positive future transactions as well. + pub fn pending_hashes( + &self, + nonce: N, + ) -> BTreeSet where + N: Fn(&Address) -> Option, + { + let ready = ready::OptionalState::new(nonce); + self.pool.read().unordered_pending(ready).map(|tx| tx.hash).collect() + } + /// Returns current pending transactions ordered by priority. /// /// NOTE: This may return a cached version of pending transaction set. @@ -322,10 +406,11 @@ impl TransactionQueue { } /// Culls all stalled transactions from the pool. - pub fn cull( + pub fn cull( &self, client: C, ) { + trace_time!("pool::cull"); // We don't care about future transactions, so nonce_cap is not important. let nonce_cap = None; // We want to clear stale transactions from the queue as well. @@ -340,9 +425,19 @@ impl TransactionQueue { current_id.checked_sub(gap) }; - let state_readiness = ready::State::new(client, stale_id, nonce_cap); + self.recently_rejected.clear(); - let removed = self.pool.write().cull(None, state_readiness); + let mut removed = 0; + let senders: Vec<_> = { + let pool = self.pool.read(); + let senders = pool.senders().cloned().collect(); + senders + }; + for chunk in senders.chunks(CULL_SENDERS_CHUNK) { + trace_time!("pool::cull::chunk"); + let state_readiness = ready::State::new(client.clone(), stale_id, nonce_cap); + removed += self.pool.write().cull(Some(chunk), state_readiness); + } debug!(target: "txqueue", "Removed {} stalled transactions. {}", removed, self.status()); } diff --git a/miner/src/pool/ready.rs b/miner/src/pool/ready.rs index 0b4d27f7f2c..4ad7f05ee66 100644 --- a/miner/src/pool/ready.rs +++ b/miner/src/pool/ready.rs @@ -129,6 +129,43 @@ impl txpool::Ready for Condition { } } +/// Readiness checker that only relies on nonce cache (does actually go to state). +/// +/// Checks readiness of transactions by comparing the nonce to state nonce. If nonce +/// isn't found in provided state nonce store, defaults to the tx nonce and updates +/// the nonce store. Useful for using with a state nonce cache when false positives are allowed. +pub struct OptionalState { + nonces: HashMap, + state: C, +} + +impl OptionalState { + pub fn new(state: C) -> Self { + OptionalState { + nonces: Default::default(), + state, + } + } +} + +impl Option> txpool::Ready for OptionalState { + fn is_ready(&mut self, tx: &VerifiedTransaction) -> txpool::Readiness { + let sender = tx.sender(); + let state = &self.state; + let nonce = self.nonces.entry(*sender).or_insert_with(|| { + state(sender).unwrap_or_else(|| tx.transaction.nonce) + }); + match tx.transaction.nonce.cmp(nonce) { + cmp::Ordering::Greater => txpool::Readiness::Future, + cmp::Ordering::Less => txpool::Readiness::Stale, + cmp::Ordering::Equal => { + *nonce = *nonce + 1.into(); + txpool::Readiness::Ready + }, + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/miner/src/pool/scoring.rs b/miner/src/pool/scoring.rs index 54e792af9eb..3592204054d 100644 --- a/miner/src/pool/scoring.rs +++ b/miner/src/pool/scoring.rs @@ -30,7 +30,7 @@ use std::cmp; use ethereum_types::U256; -use txpool; +use txpool::{self, scoring}; use super::{verifier, PrioritizationStrategy, VerifiedTransaction}; /// Transaction with the same (sender, nonce) can be replaced only if @@ -75,9 +75,9 @@ impl txpool::Scoring for NonceAndGasPrice { old.transaction.nonce.cmp(&other.transaction.nonce) } - fn choose(&self, old: &VerifiedTransaction, new: &VerifiedTransaction) -> txpool::scoring::Choice { + fn choose(&self, old: &VerifiedTransaction, new: &VerifiedTransaction) -> scoring::Choice { if old.transaction.nonce != new.transaction.nonce { - return txpool::scoring::Choice::InsertNew + return scoring::Choice::InsertNew } let old_gp = old.transaction.gas_price; @@ -86,13 +86,13 @@ impl txpool::Scoring for NonceAndGasPrice { let min_required_gp = bump_gas_price(old_gp); match min_required_gp.cmp(&new_gp) { - cmp::Ordering::Greater => txpool::scoring::Choice::RejectNew, - _ => txpool::scoring::Choice::ReplaceOld, + cmp::Ordering::Greater => scoring::Choice::RejectNew, + _ => scoring::Choice::ReplaceOld, } } - fn update_scores(&self, txs: &[txpool::Transaction], scores: &mut [U256], change: txpool::scoring::Change) { - use self::txpool::scoring::Change; + fn update_scores(&self, txs: &[txpool::Transaction], scores: &mut [U256], change: scoring::Change) { + use self::scoring::Change; match change { Change::Culled(_) => {}, @@ -122,19 +122,26 @@ impl txpool::Scoring for NonceAndGasPrice { } } - fn should_replace(&self, old: &VerifiedTransaction, new: &VerifiedTransaction) -> bool { + fn should_replace(&self, old: &VerifiedTransaction, new: &VerifiedTransaction) -> scoring::Choice { if old.sender == new.sender { // prefer earliest transaction match new.transaction.nonce.cmp(&old.transaction.nonce) { - cmp::Ordering::Less => true, - cmp::Ordering::Greater => false, - cmp::Ordering::Equal => self.choose(old, new) == txpool::scoring::Choice::ReplaceOld, + cmp::Ordering::Less => scoring::Choice::ReplaceOld, + cmp::Ordering::Greater => scoring::Choice::RejectNew, + cmp::Ordering::Equal => self.choose(old, new), } + } else if old.priority().is_local() && new.priority().is_local() { + // accept local transactions over the limit + scoring::Choice::InsertNew } else { let old_score = (old.priority(), old.transaction.gas_price); let new_score = (new.priority(), new.transaction.gas_price); - new_score > old_score - } + if new_score > old_score { + scoring::Choice::ReplaceOld + } else { + scoring::Choice::RejectNew + } + } } } @@ -146,6 +153,7 @@ mod tests { use ethkey::{Random, Generator}; use pool::tests::tx::{Tx, TxExt}; use txpool::Scoring; + use txpool::scoring::Choice::*; #[test] fn should_replace_same_sender_by_nonce() { @@ -181,14 +189,14 @@ mod tests { } }).collect::>(); - assert!(!scoring.should_replace(&txs[0], &txs[1])); - assert!(scoring.should_replace(&txs[1], &txs[0])); + assert_eq!(scoring.should_replace(&txs[0], &txs[1]), RejectNew); + assert_eq!(scoring.should_replace(&txs[1], &txs[0]), ReplaceOld); - assert!(!scoring.should_replace(&txs[1], &txs[2])); - assert!(!scoring.should_replace(&txs[2], &txs[1])); + assert_eq!(scoring.should_replace(&txs[1], &txs[2]), RejectNew); + assert_eq!(scoring.should_replace(&txs[2], &txs[1]), RejectNew); - assert!(scoring.should_replace(&txs[1], &txs[3])); - assert!(!scoring.should_replace(&txs[3], &txs[1])); + assert_eq!(scoring.should_replace(&txs[1], &txs[3]), ReplaceOld); + assert_eq!(scoring.should_replace(&txs[3], &txs[1]), RejectNew); } #[test] @@ -246,14 +254,14 @@ mod tests { } }; - assert!(scoring.should_replace(&tx_regular_low_gas, &tx_regular_high_gas)); - assert!(!scoring.should_replace(&tx_regular_high_gas, &tx_regular_low_gas)); + assert_eq!(scoring.should_replace(&tx_regular_low_gas, &tx_regular_high_gas), ReplaceOld); + assert_eq!(scoring.should_replace(&tx_regular_high_gas, &tx_regular_low_gas), RejectNew); - assert!(scoring.should_replace(&tx_regular_high_gas, &tx_local_low_gas)); - assert!(!scoring.should_replace(&tx_local_low_gas, &tx_regular_high_gas)); + assert_eq!(scoring.should_replace(&tx_regular_high_gas, &tx_local_low_gas), ReplaceOld); + assert_eq!(scoring.should_replace(&tx_local_low_gas, &tx_regular_high_gas), RejectNew); - assert!(scoring.should_replace(&tx_local_low_gas, &tx_local_high_gas)); - assert!(!scoring.should_replace(&tx_local_high_gas, &tx_regular_low_gas)); + assert_eq!(scoring.should_replace(&tx_local_low_gas, &tx_local_high_gas), InsertNew); + assert_eq!(scoring.should_replace(&tx_local_high_gas, &tx_regular_low_gas), RejectNew); } #[test] @@ -277,35 +285,35 @@ mod tests { // No update required let mut scores = initial_scores.clone(); - scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::Culled(0)); - scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::Culled(1)); - scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::Culled(2)); + scoring.update_scores(&transactions, &mut *scores, scoring::Change::Culled(0)); + scoring.update_scores(&transactions, &mut *scores, scoring::Change::Culled(1)); + scoring.update_scores(&transactions, &mut *scores, scoring::Change::Culled(2)); assert_eq!(scores, initial_scores); let mut scores = initial_scores.clone(); - scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::RemovedAt(0)); - scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::RemovedAt(1)); - scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::RemovedAt(2)); + scoring.update_scores(&transactions, &mut *scores, scoring::Change::RemovedAt(0)); + scoring.update_scores(&transactions, &mut *scores, scoring::Change::RemovedAt(1)); + scoring.update_scores(&transactions, &mut *scores, scoring::Change::RemovedAt(2)); assert_eq!(scores, initial_scores); // Compute score at given index let mut scores = initial_scores.clone(); - scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::InsertedAt(0)); + scoring.update_scores(&transactions, &mut *scores, scoring::Change::InsertedAt(0)); assert_eq!(scores, vec![32768.into(), 0.into(), 0.into()]); - scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::InsertedAt(1)); + scoring.update_scores(&transactions, &mut *scores, scoring::Change::InsertedAt(1)); assert_eq!(scores, vec![32768.into(), 1024.into(), 0.into()]); - scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::InsertedAt(2)); + scoring.update_scores(&transactions, &mut *scores, scoring::Change::InsertedAt(2)); assert_eq!(scores, vec![32768.into(), 1024.into(), 1.into()]); let mut scores = initial_scores.clone(); - scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::ReplacedAt(0)); + scoring.update_scores(&transactions, &mut *scores, scoring::Change::ReplacedAt(0)); assert_eq!(scores, vec![32768.into(), 0.into(), 0.into()]); - scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::ReplacedAt(1)); + scoring.update_scores(&transactions, &mut *scores, scoring::Change::ReplacedAt(1)); assert_eq!(scores, vec![32768.into(), 1024.into(), 0.into()]); - scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::ReplacedAt(2)); + scoring.update_scores(&transactions, &mut *scores, scoring::Change::ReplacedAt(2)); assert_eq!(scores, vec![32768.into(), 1024.into(), 1.into()]); // Check penalization - scoring.update_scores(&transactions, &mut *scores, txpool::scoring::Change::Event(())); + scoring.update_scores(&transactions, &mut *scores, scoring::Change::Event(())); assert_eq!(scores, vec![32768.into(), 128.into(), 0.into()]); } } diff --git a/miner/src/pool/tests/mod.rs b/miner/src/pool/tests/mod.rs index df637a6cfbe..b5cbaab6319 100644 --- a/miner/src/pool/tests/mod.rs +++ b/miner/src/pool/tests/mod.rs @@ -41,7 +41,6 @@ fn new_queue() -> TransactionQueue { PrioritizationStrategy::GasPriceOnly, ) } - #[test] fn should_return_correct_nonces_when_dropped_because_of_limit() { // given @@ -63,8 +62,8 @@ fn should_return_correct_nonces_when_dropped_because_of_limit() { let nonce = tx1.nonce; // when - let r1= txq.import(TestClient::new(), vec![tx1].local()); - let r2= txq.import(TestClient::new(), vec![tx2].local()); + let r1 = txq.import(TestClient::new(), vec![tx1].retracted()); + let r2 = txq.import(TestClient::new(), vec![tx2].retracted()); assert_eq!(r1, vec![Ok(())]); assert_eq!(r2, vec![Err(transaction::Error::LimitReached)]); assert_eq!(txq.status().status.transaction_count, 1); @@ -77,17 +76,68 @@ fn should_return_correct_nonces_when_dropped_because_of_limit() { let tx2 = Tx::gas_price(2).signed(); let tx3 = Tx::gas_price(1).signed(); let tx4 = Tx::gas_price(3).signed(); - let res = txq.import(TestClient::new(), vec![tx1, tx2].local()); - let res2 = txq.import(TestClient::new(), vec![tx3, tx4].local()); + let res = txq.import(TestClient::new(), vec![tx1, tx2].retracted()); + let res2 = txq.import(TestClient::new(), vec![tx3, tx4].retracted()); // then assert_eq!(res, vec![Ok(()), Ok(())]); - assert_eq!(res2, vec![Err(transaction::Error::LimitReached), Ok(())]); + assert_eq!(res2, vec![ + // The error here indicates reaching the limit + // and minimal effective gas price taken into account. + Err(transaction::Error::InsufficientGasPrice { minimal: 2.into(), got: 1.into() }), + Ok(()) + ]); assert_eq!(txq.status().status.transaction_count, 3); // First inserted transacton got dropped because of limit assert_eq!(txq.next_nonce(TestClient::new(), &sender), None); } +#[test] +fn should_never_drop_local_transactions_from_different_senders() { + // given + let txq = TransactionQueue::new( + txpool::Options { + max_count: 3, + max_per_sender: 1, + max_mem_usage: 50 + }, + verifier::Options { + minimal_gas_price: 1.into(), + block_gas_limit: 1_000_000.into(), + tx_gas_limit: 1_000_000.into(), + }, + PrioritizationStrategy::GasPriceOnly, + ); + let (tx1, tx2) = Tx::gas_price(2).signed_pair(); + let sender = tx1.sender(); + let nonce = tx1.nonce; + + // when + let r1 = txq.import(TestClient::new(), vec![tx1].local()); + let r2 = txq.import(TestClient::new(), vec![tx2].local()); + assert_eq!(r1, vec![Ok(())]); + // max-per-sender is reached, that's ok. + assert_eq!(r2, vec![Err(transaction::Error::LimitReached)]); + assert_eq!(txq.status().status.transaction_count, 1); + + // then + assert_eq!(txq.next_nonce(TestClient::new(), &sender), Some(nonce + 1.into())); + + // when + let tx1 = Tx::gas_price(2).signed(); + let tx2 = Tx::gas_price(2).signed(); + let tx3 = Tx::gas_price(1).signed(); + let tx4 = Tx::gas_price(3).signed(); + let res = txq.import(TestClient::new(), vec![tx1, tx2].local()); + let res2 = txq.import(TestClient::new(), vec![tx3, tx4].local()); + + // then + assert_eq!(res, vec![Ok(()), Ok(())]); + assert_eq!(res2, vec![Ok(()), Ok(())]); + assert_eq!(txq.status().status.transaction_count, 5); + assert_eq!(txq.next_nonce(TestClient::new(), &sender), Some(nonce + 1.into())); +} + #[test] fn should_handle_same_transaction_imported_twice_with_different_state_nonces() { // given @@ -893,6 +943,47 @@ fn should_avoid_verifying_transaction_already_in_pool() { assert_eq!(txq.status().status.transaction_count, 1); } +#[test] +fn should_avoid_reverifying_recently_rejected_transactions() { + // given + let txq = TransactionQueue::new( + txpool::Options { + max_count: 1, + max_per_sender: 2, + max_mem_usage: 50 + }, + verifier::Options { + minimal_gas_price: 1.into(), + block_gas_limit: 1_000_000.into(), + tx_gas_limit: 1_000_000.into(), + }, + PrioritizationStrategy::GasPriceOnly, + ); + + let client = TestClient::new(); + let tx1 = Tx::gas_price(10_000).signed().unverified(); + + let res = txq.import(client.clone(), vec![tx1.clone()]); + assert_eq!(res, vec![Err(transaction::Error::InsufficientBalance { + balance: 0xf67c.into(), + cost: 0xc8458e4.into(), + })]); + assert_eq!(txq.status().status.transaction_count, 0); + assert!(client.was_verification_triggered()); + + // when + let client = TestClient::new(); + let res = txq.import(client.clone(), vec![tx1]); + assert_eq!(res, vec![Err(transaction::Error::InsufficientBalance { + balance: 0xf67c.into(), + cost: 0xc8458e4.into(), + })]); + assert!(!client.was_verification_triggered()); + + // then + assert_eq!(txq.status().status.transaction_count, 0); +} + #[test] fn should_reject_early_in_case_gas_price_is_less_than_min_effective() { // given diff --git a/miner/src/work_notify.rs b/miner/src/work_notify.rs index 8825fd4b65f..efae26ff114 100644 --- a/miner/src/work_notify.rs +++ b/miner/src/work_notify.rs @@ -62,7 +62,7 @@ impl WorkPoster { client: fetch, remote: remote, urls: urls, - seed_compute: Mutex::new(SeedHashCompute::new()), + seed_compute: Mutex::new(SeedHashCompute::default()), } } } diff --git a/parity-clib-example/CMakeLists.txt b/parity-clib-examples/cpp/CMakeLists.txt similarity index 100% rename from parity-clib-example/CMakeLists.txt rename to parity-clib-examples/cpp/CMakeLists.txt diff --git a/parity-clib-example/main.cpp b/parity-clib-examples/cpp/main.cpp similarity index 100% rename from parity-clib-example/main.cpp rename to parity-clib-examples/cpp/main.cpp diff --git a/parity/blockchain.rs b/parity/blockchain.rs index 8e23cedf183..1ea64b67bbb 100644 --- a/parity/blockchain.rs +++ b/parity/blockchain.rs @@ -352,7 +352,7 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> { algorithm, cmd.pruning_history, cmd.pruning_memory, - cmd.check_seal + cmd.check_seal, ); client_config.queue.verifier_settings = cmd.verifier_settings; diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index e00567231a6..b16dcfd9794 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -258,7 +258,7 @@ usage! { ARG arg_mode: (String) = "last", or |c: &Config| c.parity.as_ref()?.mode.clone(), "--mode=[MODE]", - "Set the operating mode. MODE can be one of: last - Uses the last-used mode, active if none; active - Parity continuously syncs the chain; passive - Parity syncs initially, then sleeps and wakes regularly to resync; dark - Parity syncs only when the RPC is active; offline - Parity doesn't sync.", + "Set the operating mode. MODE can be one of: last - Uses the last-used mode, active if none; active - Parity continuously syncs the chain; passive - Parity syncs initially, then sleeps and wakes regularly to resync; dark - Parity syncs only when the JSON-RPC is active; offline - Parity doesn't sync.", ARG arg_mode_timeout: (u64) = 300u64, or |c: &Config| c.parity.as_ref()?.mode_timeout.clone(), "--mode-timeout=[SECS]", @@ -315,7 +315,7 @@ usage! { ARG arg_ports_shift: (u16) = 0u16, or |c: &Config| c.misc.as_ref()?.ports_shift, "--ports-shift=[SHIFT]", - "Add SHIFT to all port numbers Parity is listening on. Includes network port and all servers (RPC, WebSockets, UI, IPFS, SecretStore).", + "Add SHIFT to all port numbers Parity is listening on. Includes network port and all servers (HTTP JSON-RPC, WebSockets JSON-RPC, IPFS, SecretStore).", ["Account Options"] FLAG flag_no_hardware_wallets: (bool) = false, or |c: &Config| c.account.as_ref()?.disable_hardware.clone(), @@ -449,22 +449,33 @@ usage! { "--reserved-peers=[FILE]", "Provide a file containing enodes, one per line. These nodes will always have a reserved slot on top of the normal maximum peers.", - ["API and Console Options – RPC"] + CHECK |args: &Args| { + if let (Some(max_peers), Some(min_peers)) = (args.arg_max_peers, args.arg_min_peers) { + if min_peers > max_peers { + return Err(ArgsError::PeerConfiguration); + } + } + + Ok(()) + }, + + + ["API and Console Options – HTTP JSON-RPC"] FLAG flag_no_jsonrpc: (bool) = false, or |c: &Config| c.rpc.as_ref()?.disable.clone(), "--no-jsonrpc", - "Disable the JSON-RPC API server.", + "Disable the HTTP JSON-RPC API server.", ARG arg_jsonrpc_port: (u16) = 8545u16, or |c: &Config| c.rpc.as_ref()?.port.clone(), "--jsonrpc-port=[PORT]", - "Specify the port portion of the JSONRPC API server.", + "Specify the port portion of the HTTP JSON-RPC API server.", ARG arg_jsonrpc_interface: (String) = "local", or |c: &Config| c.rpc.as_ref()?.interface.clone(), "--jsonrpc-interface=[IP]", - "Specify the hostname portion of the JSONRPC API server, IP should be an interface's IP address, or all (all interfaces) or local.", + "Specify the hostname portion of the HTTP JSON-RPC API server, IP should be an interface's IP address, or all (all interfaces) or local.", ARG arg_jsonrpc_apis: (String) = "web3,eth,pubsub,net,parity,private,parity_pubsub,traces,rpc,shh,shh_pubsub", or |c: &Config| c.rpc.as_ref()?.apis.as_ref().map(|vec| vec.join(",")), "--jsonrpc-apis=[APIS]", - "Specify the APIs available through the JSONRPC interface using a comma-delimited list of API names. Possible names are: all, safe, web3, net, eth, pubsub, personal, signer, parity, parity_pubsub, parity_accounts, parity_set, traces, rpc, secretstore, shh, shh_pubsub. You can also disable a specific API by putting '-' in the front, example: all,-personal. safe contains following apis: web3, net, eth, pubsub, parity, parity_pubsub, traces, rpc, shh, shh_pubsub", + "Specify the APIs available through the HTTP JSON-RPC interface using a comma-delimited list of API names. Possible names are: all, safe, web3, net, eth, pubsub, personal, signer, parity, parity_pubsub, parity_accounts, parity_set, traces, rpc, secretstore, shh, shh_pubsub. You can also disable a specific API by putting '-' in the front, example: all,-personal. safe contains following apis: web3, net, eth, pubsub, parity, parity_pubsub, traces, rpc, shh, shh_pubsub", ARG arg_jsonrpc_hosts: (String) = "none", or |c: &Config| c.rpc.as_ref()?.hosts.as_ref().map(|vec| vec.join(",")), "--jsonrpc-hosts=[HOSTS]", @@ -472,11 +483,11 @@ usage! { ARG arg_jsonrpc_threads: (usize) = 4usize, or |c: &Config| c.rpc.as_ref()?.processing_threads, "--jsonrpc-threads=[THREADS]", - "Turn on additional processing threads in all RPC servers. Setting this to non-zero value allows parallel cpu-heavy queries execution.", + "Turn on additional processing threads in all HTTP JSON-RPC servers. Setting this to non-zero value allows parallel cpu-heavy queries execution.", ARG arg_jsonrpc_cors: (String) = "none", or |c: &Config| c.rpc.as_ref()?.cors.as_ref().map(|vec| vec.join(",")), "--jsonrpc-cors=[URL]", - "Specify CORS header for JSON-RPC API responses. Special options: \"all\", \"none\".", + "Specify CORS header for HTTP JSON-RPC API responses. Special options: \"all\", \"none\".", ARG arg_jsonrpc_server_threads: (Option) = None, or |c: &Config| c.rpc.as_ref()?.server_threads, "--jsonrpc-server-threads=[NUM]", @@ -484,24 +495,24 @@ usage! { ARG arg_jsonrpc_max_payload: (Option) = None, or |c: &Config| c.rpc.as_ref()?.max_payload, "--jsonrpc-max-payload=[MB]", - "Specify maximum size for RPC requests in megabytes.", + "Specify maximum size for HTTP JSON-RPC requests in megabytes.", ["API and Console Options – WebSockets"] FLAG flag_no_ws: (bool) = false, or |c: &Config| c.websockets.as_ref()?.disable.clone(), "--no-ws", - "Disable the WebSockets server.", + "Disable the WebSockets JSON-RPC server.", ARG arg_ws_port: (u16) = 8546u16, or |c: &Config| c.websockets.as_ref()?.port.clone(), "--ws-port=[PORT]", - "Specify the port portion of the WebSockets server.", + "Specify the port portion of the WebSockets JSON-RPC server.", ARG arg_ws_interface: (String) = "local", or |c: &Config| c.websockets.as_ref()?.interface.clone(), "--ws-interface=[IP]", - "Specify the hostname portion of the WebSockets server, IP should be an interface's IP address, or all (all interfaces) or local.", + "Specify the hostname portion of the WebSockets JSON-RPC server, IP should be an interface's IP address, or all (all interfaces) or local.", ARG arg_ws_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,private,traces,rpc,shh,shh_pubsub", or |c: &Config| c.websockets.as_ref()?.apis.as_ref().map(|vec| vec.join(",")), "--ws-apis=[APIS]", - "Specify the APIs available through the WebSockets interface using a comma-delimited list of API names. Possible names are: all, safe, web3, net, eth, pubsub, personal, signer, parity, parity_pubsub, parity_accounts, parity_set, traces, rpc, secretstore, shh, shh_pubsub. You can also disable a specific API by putting '-' in the front, example: all,-personal. safe contains following apis: web3, net, eth, pubsub, parity, parity_pubsub, traces, rpc, shh, shh_pubsub", + "Specify the JSON-RPC APIs available through the WebSockets interface using a comma-delimited list of API names. Possible names are: all, safe, web3, net, eth, pubsub, personal, signer, parity, parity_pubsub, parity_accounts, parity_set, traces, rpc, secretstore, shh, shh_pubsub. You can also disable a specific API by putting '-' in the front, example: all,-personal. safe contains following apis: web3, net, eth, pubsub, parity, parity_pubsub, traces, rpc, shh, shh_pubsub", ARG arg_ws_origins: (String) = "parity://*,chrome-extension://*,moz-extension://*", or |c: &Config| c.websockets.as_ref()?.origins.as_ref().map(|vec| vec.join(",")), "--ws-origins=[URL]", @@ -513,7 +524,7 @@ usage! { ARG arg_ws_max_connections: (usize) = 100usize, or |c: &Config| c.websockets.as_ref()?.max_connections, "--ws-max-connections=[CONN]", - "Maximal number of allowed concurrent WS connections.", + "Maximal number of allowed concurrent WebSockets JSON-RPC connections.", ["API and Console Options – IPC"] FLAG flag_no_ipc: (bool) = false, or |c: &Config| c.ipc.as_ref()?.disable.clone(), @@ -646,7 +657,7 @@ usage! { FLAG flag_tx_queue_no_unfamiliar_locals: (bool) = false, or |c: &Config| c.mining.as_ref()?.tx_queue_no_unfamiliar_locals.clone(), "--tx-queue-no-unfamiliar-locals", - "Transactions received via local means (RPC, WS, etc) will be treated as external if the sending account is unknown.", + "Transactions received via local means (HTTP JSON-RPC, WebSockets JSON-RPC, etc) will be treated as external if the sending account is unknown.", FLAG flag_refuse_service_transactions: (bool) = false, or |c: &Config| c.mining.as_ref()?.refuse_service_transactions.clone(), "--refuse-service-transactions", @@ -875,45 +886,30 @@ usage! { "Target size of the whisper message pool in megabytes.", ["Legacy Options"] - FLAG flag_warp: (bool) = false, or |_| None, - "--warp", - "Does nothing; warp sync is enabled by default. Use --no-warp to disable.", - - FLAG flag_fast_and_loose: (bool) = false, or |_| None, - "--fast-and-loose", - "Does nothing; DB WAL is always activated.", - - FLAG flag_dapps_apis_all: (bool) = false, or |_| None, - "--dapps-apis-all", - "Dapps server is merged with RPC server. Use --jsonrpc-apis.", + // Options that are hidden from config, but are still unique for its functionality. FLAG flag_geth: (bool) = false, or |_| None, "--geth", "Run in Geth-compatibility mode. Sets the IPC path to be the same as Geth's. Overrides the --ipc-path and --ipcpath options. Alters RPCs to reflect Geth bugs. Includes the personal_ RPC by default.", - FLAG flag_testnet: (bool) = false, or |_| None, - "--testnet", - "Testnet mode. Equivalent to --chain testnet. Overrides the --keys-path option.", - FLAG flag_import_geth_keys: (bool) = false, or |_| None, "--import-geth-keys", "Attempt to import keys from Geth client.", - FLAG flag_ipcdisable: (bool) = false, or |_| None, - "--ipcdisable", - "Equivalent to --no-ipc.", - - FLAG flag_ipc_off: (bool) = false, or |_| None, - "--ipc-off", - "Equivalent to --no-ipc.", + // Options that either do nothing, or are replaced by other options. + // FLAG Removed in 1.6 or before. - FLAG flag_nodiscover: (bool) = false, or |_| None, - "--nodiscover", - "Equivalent to --no-discovery.", + FLAG flag_warp: (bool) = false, or |_| None, + "--warp", + "Does nothing; warp sync is enabled by default. Use --no-warp to disable.", FLAG flag_jsonrpc: (bool) = false, or |_| None, "-j, --jsonrpc", - "Does nothing; JSON-RPC is on by default now.", + "Does nothing; HTTP JSON-RPC is on by default now.", + + FLAG flag_rpc: (bool) = false, or |_| None, + "--rpc", + "Does nothing; HTTP JSON-RPC is on by default now.", FLAG flag_jsonrpc_off: (bool) = false, or |_| None, "--jsonrpc-off", @@ -921,15 +917,35 @@ usage! { FLAG flag_webapp: (bool) = false, or |_| None, "-w, --webapp", - "Does nothing; dapps server is on by default now.", + "Does nothing; dapps server has been removed.", FLAG flag_dapps_off: (bool) = false, or |_| None, "--dapps-off", "Equivalent to --no-dapps.", - FLAG flag_rpc: (bool) = false, or |_| None, - "--rpc", - "Does nothing; JSON-RPC is on by default now.", + FLAG flag_ipcdisable: (bool) = false, or |_| None, + "--ipcdisable", + "Equivalent to --no-ipc.", + + FLAG flag_ipc_off: (bool) = false, or |_| None, + "--ipc-off", + "Equivalent to --no-ipc.", + + FLAG flag_testnet: (bool) = false, or |_| None, + "--testnet", + "Testnet mode. Equivalent to --chain testnet. Overrides the --keys-path option.", + + FLAG flag_nodiscover: (bool) = false, or |_| None, + "--nodiscover", + "Equivalent to --no-discovery.", + + // FLAG Removed in 1.7. + + FLAG flag_dapps_apis_all: (bool) = false, or |_| None, + "--dapps-apis-all", + "Dapps server is merged with HTTP JSON-RPC server. Use --jsonrpc-apis.", + + // FLAG Removed in 1.11. FLAG flag_public_node: (bool) = false, or |_| None, "--public-node", @@ -947,41 +963,21 @@ usage! { "--ui-no-validation", "Does nothing; UI is now a separate project.", - ARG arg_ui_interface: (String) = "local", or |_| None, - "--ui-interface=[IP]", - "Does nothing; UI is now a separate project.", - - ARG arg_ui_hosts: (String) = "none", or |_| None, - "--ui-hosts=[HOSTS]", - "Does nothing; UI is now a separate project.", - - ARG arg_ui_port: (u16) = 8180u16, or |_| None, - "--ui-port=[PORT]", - "Does nothing; UI is now a separate project.", + // FLAG Removed in 2.0. - ARG arg_dapps_port: (Option) = None, or |c: &Config| c.dapps.as_ref()?.port.clone(), - "--dapps-port=[PORT]", - "Dapps server is merged with RPC server. Use --jsonrpc-port.", - - ARG arg_dapps_interface: (Option) = None, or |c: &Config| c.dapps.as_ref()?.interface.clone(), - "--dapps-interface=[IP]", - "Dapps server is merged with RPC server. Use --jsonrpc-interface.", - - ARG arg_dapps_hosts: (Option) = None, or |c: &Config| c.dapps.as_ref()?.hosts.as_ref().map(|vec| vec.join(",")), - "--dapps-hosts=[HOSTS]", - "Dapps server is merged with RPC server. Use --jsonrpc-hosts.", + FLAG flag_fast_and_loose: (bool) = false, or |_| None, + "--fast-and-loose", + "Does nothing; DB WAL is always activated.", - ARG arg_dapps_cors: (Option) = None, or |c: &Config| c.dapps.as_ref()?.cors.clone(), - "--dapps-cors=[URL]", - "Dapps server is merged with RPC server. Use --jsonrpc-cors.", + // ARG Removed in 1.6 or before. - ARG arg_dapps_user: (Option) = None, or |c: &Config| c.dapps.as_ref()?.user.clone(), - "--dapps-user=[USERNAME]", - "Dapps server authentication has been removed.", + ARG arg_etherbase: (Option) = None, or |_| None, + "--etherbase=[ADDRESS]", + "Equivalent to --author ADDRESS.", - ARG arg_dapps_pass: (Option) = None, or |c: &Config| c.dapps.as_ref()?.pass.clone(), - "--dapps-pass=[PASSWORD]", - "Dapps server authentication has been removed.", + ARG arg_extradata: (Option) = None, or |_| None, + "--extradata=[STRING]", + "Equivalent to --extra-data STRING.", ARG arg_datadir: (Option) = None, or |_| None, "--datadir=[PATH]", @@ -1027,23 +1023,55 @@ usage! { "--gasprice=[WEI]", "Equivalent to --min-gas-price WEI.", - ARG arg_etherbase: (Option) = None, or |_| None, - "--etherbase=[ADDRESS]", - "Equivalent to --author ADDRESS.", - - ARG arg_extradata: (Option) = None, or |_| None, - "--extradata=[STRING]", - "Equivalent to --extra-data STRING.", - ARG arg_cache: (Option) = None, or |_| None, "--cache=[MB]", "Equivalent to --cache-size MB.", - ARG arg_tx_queue_ban_count: (u16) = 1u16, or |c: &Config| c.mining.as_ref()?.tx_queue_ban_count.clone(), + // ARG Removed in 1.7. + + ARG arg_dapps_port: (Option) = None, or |c: &Config| c.dapps.as_ref()?.port.clone(), + "--dapps-port=[PORT]", + "Does nothing; dapps server has been removed.", + + ARG arg_dapps_interface: (Option) = None, or |c: &Config| c.dapps.as_ref()?.interface.clone(), + "--dapps-interface=[IP]", + "Does nothing; dapps server has been removed.", + + ARG arg_dapps_hosts: (Option) = None, or |c: &Config| c.dapps.as_ref()?.hosts.as_ref().map(|vec| vec.join(",")), + "--dapps-hosts=[HOSTS]", + "Does nothing; dapps server has been removed.", + + ARG arg_dapps_cors: (Option) = None, or |c: &Config| c.dapps.as_ref()?.cors.clone(), + "--dapps-cors=[URL]", + "Does nothing; dapps server has been removed.", + + ARG arg_dapps_user: (Option) = None, or |c: &Config| c.dapps.as_ref()?.user.clone(), + "--dapps-user=[USERNAME]", + "Dapps server authentication has been removed.", + + ARG arg_dapps_pass: (Option) = None, or |c: &Config| c.dapps.as_ref()?.pass.clone(), + "--dapps-pass=[PASSWORD]", + "Dapps server authentication has been removed.", + + // ARG removed in 1.11. + + ARG arg_ui_interface: (Option) = None, or |_| None, + "--ui-interface=[IP]", + "Does nothing; UI is now a separate project.", + + ARG arg_ui_hosts: (Option) = None, or |_| None, + "--ui-hosts=[HOSTS]", + "Does nothing; UI is now a separate project.", + + ARG arg_ui_port: (Option) = None, or |_| None, + "--ui-port=[PORT]", + "Does nothing; UI is now a separate project.", + + ARG arg_tx_queue_ban_count: (Option) = None, or |c: &Config| c.mining.as_ref()?.tx_queue_ban_count.clone(), "--tx-queue-ban-count=[C]", "Not supported.", - ARG arg_tx_queue_ban_time: (u16) = 180u16, or |c: &Config| c.mining.as_ref()?.tx_queue_ban_time.clone(), + ARG arg_tx_queue_ban_time: (Option) = None, or |c: &Config| c.mining.as_ref()?.tx_queue_ban_time.clone(), "--tx-queue-ban-time=[SEC]", "Not supported.", } @@ -1427,11 +1455,11 @@ mod tests { let args = Args::parse(&["parity", "--password", "~/.safe/1", "--password", "~/.safe/2", "--ui-port", "8123"]).unwrap(); assert_eq!(args.arg_password, vec!["~/.safe/1".to_owned(), "~/.safe/2".to_owned()]); - assert_eq!(args.arg_ui_port, 8123); + assert_eq!(args.arg_ui_port, Some(8123)); let args = Args::parse(&["parity", "--password", "~/.safe/1,~/.safe/2", "--ui-port", "8123"]).unwrap(); assert_eq!(args.arg_password, vec!["~/.safe/1".to_owned(), "~/.safe/2".to_owned()]); - assert_eq!(args.arg_ui_port, 8123); + assert_eq!(args.arg_ui_port, Some(8123)); } #[test] @@ -1583,9 +1611,9 @@ mod tests { flag_force_ui: false, flag_no_ui: false, - arg_ui_port: 8180u16, - arg_ui_interface: "local".into(), - arg_ui_hosts: "none".into(), + arg_ui_port: None, + arg_ui_interface: None, + arg_ui_hosts: None, arg_ui_path: "$HOME/.parity/signer".into(), flag_ui_no_validation: false, @@ -1692,8 +1720,8 @@ mod tests { arg_tx_queue_mem_limit: 4u32, arg_tx_queue_gas: "off".into(), arg_tx_queue_strategy: "gas_factor".into(), - arg_tx_queue_ban_count: 1u16, - arg_tx_queue_ban_time: 180u16, + arg_tx_queue_ban_count: Some(1u16), + arg_tx_queue_ban_time: Some(180u16), flag_remove_solved: false, arg_notify_work: Some("http://localhost:3001".into()), flag_refuse_service_transactions: false, diff --git a/parity/cli/usage.rs b/parity/cli/usage.rs index 704aa5d6f1d..caacd364f2c 100644 --- a/parity/cli/usage.rs +++ b/parity/cli/usage.rs @@ -135,6 +135,9 @@ macro_rules! usage { $( ARG $arg:ident : ($($arg_type_tt:tt)+) = $arg_default:expr, or $arg_from_config:expr, $arg_usage:expr, $arg_help:expr, )* + $( + CHECK $check:expr, + )* )* } ) => { @@ -318,13 +321,6 @@ macro_rules! usage { pub fn parse>(command: &[S]) -> Result { let raw_args = RawArgs::parse(command)?; - if let (Some(max_peers), Some(min_peers)) = (raw_args.arg_max_peers, raw_args.arg_min_peers) { - // Invalid configuration pattern `mix_peers` > `max_peers` - if min_peers > max_peers { - return Err(ArgsError::PeerConfiguration); - } - } - // Skip loading config file if no_config flag is specified if raw_args.flag_no_config { return Ok(raw_args.into_args(Config::default())); @@ -332,7 +328,8 @@ macro_rules! usage { let config_file = raw_args.arg_config.clone().unwrap_or_else(|| raw_args.clone().into_args(Config::default()).arg_config); let config_file = replace_home(&::dir::default_data_path(), &config_file); - match (fs::File::open(&config_file), raw_args.arg_config.clone()) { + + let args = match (fs::File::open(&config_file), raw_args.arg_config.clone()) { // Load config file (Ok(mut file), _) => { println_stderr!("Loading config file from {}", &config_file); @@ -349,7 +346,15 @@ macro_rules! usage { Err(e) => Err(ArgsError::Config(config_file, e)) } }, - } + }?; + + $( + $( + $check(&args)?; + )* + )* + + Ok(args) } #[cfg(test)] diff --git a/parity/deprecated.rs b/parity/deprecated.rs index f3e433d1389..24bd1638b1a 100644 --- a/parity/deprecated.rs +++ b/parity/deprecated.rs @@ -37,6 +37,8 @@ impl fmt::Display for Deprecated { pub fn find_deprecated(args: &Args) -> Vec { let mut result = vec![]; + // Removed in 1.6 or before. + if args.flag_warp { result.push(Deprecated::DoesNothing("--warp")); } @@ -77,21 +79,78 @@ pub fn find_deprecated(args: &Args) -> Vec { result.push(Deprecated::Replaced("--extradata", "--extra-data")); } - // Removed in 1.7 + if args.flag_testnet { + result.push(Deprecated::Replaced("--testnet", "--chain testnet")); + } + + if args.flag_nodiscover { + result.push(Deprecated::Replaced("--nodiscover", "--no-discovery")); + } + + if args.arg_datadir.is_some() { + result.push(Deprecated::Replaced("--datadir", "--base-path")); + } + + if args.arg_networkid.is_some() { + result.push(Deprecated::Replaced("--networkid", "--network-id")); + } + + if args.arg_peers.is_some() { + result.push(Deprecated::Replaced("--peers", "--min-peers")); + } + + if args.arg_nodekey.is_some() { + result.push(Deprecated::Replaced("--nodekey", "--node-key")); + } + + if args.arg_rpcaddr.is_some() { + result.push(Deprecated::Replaced("--rpcaddr", "--jsonrpc-interface")); + } + + if args.arg_rpcport.is_some() { + result.push(Deprecated::Replaced("--rpcport", "--jsonrpc-port")); + } + + if args.arg_rpcapi.is_some() { + result.push(Deprecated::Replaced("--rpcapi", "--jsonrpc-api")); + } + + if args.arg_rpccorsdomain.is_some() { + result.push(Deprecated::Replaced("--rpccorsdomain", "--jsonrpc-cors")); + } + + if args.arg_ipcapi.is_some() { + result.push(Deprecated::Replaced("--ipcapi", "--ipc-apis")); + } + + if args.arg_ipcpath.is_some() { + result.push(Deprecated::Replaced("--ipcpath", "--ipc-path")); + } + + if args.arg_gasprice.is_some() { + result.push(Deprecated::Replaced("--gasprice", "--min-gas-price")); + } + + if args.arg_cache.is_some() { + result.push(Deprecated::Replaced("--cache", "--cache-size")); + } + + // Removed in 1.7. + if args.arg_dapps_port.is_some() { - result.push(Deprecated::Replaced("--dapps-port", "--jsonrpc-port")); + result.push(Deprecated::Removed("--dapps-port")); } if args.arg_dapps_interface.is_some() { - result.push(Deprecated::Replaced("--dapps-interface", "--jsonrpc-interface")); + result.push(Deprecated::Removed("--dapps-interface")); } if args.arg_dapps_hosts.is_some() { - result.push(Deprecated::Replaced("--dapps-hosts", "--jsonrpc-hosts")); + result.push(Deprecated::Removed("--dapps-hosts")); } if args.arg_dapps_cors.is_some() { - result.push(Deprecated::Replaced("--dapps-cors", "--jsonrpc-cors")); + result.push(Deprecated::Removed("--dapps-cors")); } if args.arg_dapps_user.is_some() { @@ -106,7 +165,43 @@ pub fn find_deprecated(args: &Args) -> Vec { result.push(Deprecated::Replaced("--dapps-apis-all", "--jsonrpc-apis")); } - // Removed in 1.8 + // Removed in 1.11. + + if args.flag_public_node { + result.push(Deprecated::Removed("--public-node")); + } + + if args.flag_force_ui { + result.push(Deprecated::Removed("--force-ui")); + } + + if args.flag_no_ui { + result.push(Deprecated::Removed("--no-ui")); + } + + if args.flag_ui_no_validation { + result.push(Deprecated::Removed("--ui-no-validation")); + } + + if args.arg_ui_interface.is_some() { + result.push(Deprecated::Removed("--ui-interface")); + } + + if args.arg_ui_hosts.is_some() { + result.push(Deprecated::Removed("--ui-hosts")); + } + + if args.arg_ui_port.is_some() { + result.push(Deprecated::Removed("--ui-port")); + } + + if args.arg_tx_queue_ban_count.is_some() { + result.push(Deprecated::Removed("--tx-queue-ban-count")); + } + + if args.arg_tx_queue_ban_time.is_some() { + result.push(Deprecated::Removed("--tx-queue-ban-time")); + } result } @@ -150,10 +245,10 @@ mod tests { Deprecated::Replaced("--ipc-off", "--no-ipc"), Deprecated::Replaced("--etherbase", "--author"), Deprecated::Replaced("--extradata", "--extra-data"), - Deprecated::Replaced("--dapps-port", "--jsonrpc-port"), - Deprecated::Replaced("--dapps-interface", "--jsonrpc-interface"), - Deprecated::Replaced("--dapps-hosts", "--jsonrpc-hosts"), - Deprecated::Replaced("--dapps-cors", "--jsonrpc-cors"), + Deprecated::Removed("--dapps-port"), + Deprecated::Removed("--dapps-interface"), + Deprecated::Removed("--dapps-hosts"), + Deprecated::Removed("--dapps-cors"), Deprecated::Removed("--dapps-user"), Deprecated::Removed("--dapps-pass"), Deprecated::Replaced("--dapps-apis-all", "--jsonrpc-apis"), diff --git a/parity/params.rs b/parity/params.rs index 9417c432264..2227af3e9d2 100644 --- a/parity/params.rs +++ b/parity/params.rs @@ -24,7 +24,8 @@ use ethereum_types::{U256, Address}; use futures_cpupool::CpuPool; use hash_fetch::fetch::Client as FetchClient; use journaldb::Algorithm; -use miner::gas_pricer::{GasPricer, GasPriceCalibratorOptions}; +use miner::gas_pricer::GasPricer; +use miner::gas_price_calibrator::{GasPriceCalibratorOptions, GasPriceCalibrator}; use parity_version::version_data; use user_defaults::UserDefaults; @@ -248,12 +249,14 @@ impl GasPricerConfig { GasPricerConfig::Fixed(u) => GasPricer::Fixed(u), GasPricerConfig::Calibrated { usd_per_tx, recalibration_period, .. } => { GasPricer::new_calibrated( - GasPriceCalibratorOptions { - usd_per_tx: usd_per_tx, - recalibration_period: recalibration_period, - }, - fetch, - p, + GasPriceCalibrator::new( + GasPriceCalibratorOptions { + usd_per_tx: usd_per_tx, + recalibration_period: recalibration_period, + }, + fetch, + p, + ) ) } } diff --git a/parity/run.rs b/parity/run.rs index e784d0925ba..5ca52f80a07 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -31,6 +31,7 @@ use ethcore::verification::queue::VerifierSettings; use ethcore_logger::{Config as LogConfig, RotatingLogger}; use ethcore_service::ClientService; use sync::{self, SyncConfig}; +#[cfg(feature = "work-notify")] use miner::work_notify::WorkPoster; use futures_cpupool::CpuPool; use hash_fetch::{self, fetch}; @@ -516,6 +517,7 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: // fetch service let fetch = fetch::Client::new().map_err(|e| format!("Error starting fetch client: {:?}", e))?; + let txpool_size = cmd.miner_options.pool_limits.max_count; // create miner let miner = Arc::new(Miner::new( cmd.miner_options, @@ -526,11 +528,16 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: miner.set_author(cmd.miner_extras.author, None).expect("Fails only if password is Some; password is None; qed"); miner.set_gas_range_target(cmd.miner_extras.gas_range_target); miner.set_extra_data(cmd.miner_extras.extra_data); - if !cmd.miner_extras.work_notify.is_empty() { - miner.add_work_listener(Box::new( - WorkPoster::new(&cmd.miner_extras.work_notify, fetch.clone(), event_loop.remote()) - )); + + #[cfg(feature = "work-notify")] + { + if !cmd.miner_extras.work_notify.is_empty() { + miner.add_work_listener(Box::new( + WorkPoster::new(&cmd.miner_extras.work_notify, fetch.clone(), event_loop.remote()) + )); + } } + let engine_signer = cmd.miner_extras.engine_signer; if engine_signer != Default::default() { // Check if engine signer exists @@ -571,6 +578,7 @@ fn execute_impl(cmd: RunCmd, logger: Arc, on_client_rq: ); client_config.queue.verifier_settings = cmd.verifier_settings; + client_config.transaction_verification_queue_size = ::std::cmp::max(2048, txpool_size / 4); // set up bootnodes let mut net_conf = cmd.net_conf; diff --git a/parity/snapshot.rs b/parity/snapshot.rs index 1074bb2d3e2..0611734fd33 100644 --- a/parity/snapshot.rs +++ b/parity/snapshot.rs @@ -177,7 +177,7 @@ impl SnapshotCommand { algorithm, self.pruning_history, self.pruning_memory, - true + true, ); let restoration_db_handler = db::restoration_db_handler(&client_path, &client_config); diff --git a/parity/upgrade.rs b/parity/upgrade.rs index d98123ce13b..95fa8de823b 100644 --- a/parity/upgrade.rs +++ b/parity/upgrade.rs @@ -17,13 +17,12 @@ //! Parity upgrade logic use semver::{Version, SemVerError}; -use std::collections::*; +use std::collections::HashMap; use std::fs::{self, File, create_dir_all}; -use std::env; use std::io; use std::io::{Read, Write}; use std::path::{PathBuf, Path}; -use dir::{DatabaseDirectories, default_data_path}; +use dir::{DatabaseDirectories, default_data_path, home_dir}; use dir::helpers::replace_home; use journaldb::Algorithm; @@ -106,7 +105,7 @@ fn with_locked_version(db_path: Option<&str>, script: F) -> Result Result { let mut path = db_path.map_or({ - let mut path = env::home_dir().expect("Applications should have a home dir"); + let mut path = home_dir().expect("Applications should have a home dir"); path.push(".parity"); path }, PathBuf::from); diff --git a/parity/url.rs b/parity/url.rs index d9eb2c9d3cd..832da84908b 100644 --- a/parity/url.rs +++ b/parity/url.rs @@ -79,7 +79,7 @@ pub fn open(url: &str) -> Result<(), Error> { Ok(()) } -#[cfg(target_os="android")] +#[cfg(any(target_os="android", target_os="ios"))] pub fn open(_url: &str) -> Result<(), Error> { // TODO: While it is generally always bad to leave a function implemented, there is not much // more we can do here. This function will eventually be removed when we compile Parity diff --git a/parity/user_defaults.rs b/parity/user_defaults.rs index cb4a0a40a47..5031886f298 100644 --- a/parity/user_defaults.rs +++ b/parity/user_defaults.rs @@ -122,7 +122,7 @@ impl Default for UserDefaults { fn default() -> Self { UserDefaults { is_first_launch: true, - pruning: Algorithm::default(), + pruning: Algorithm::OverlayRecent, tracing: false, fat_db: false, mode: Mode::Active, diff --git a/price-info/Cargo.toml b/price-info/Cargo.toml index 948f09983ba..7dc648516fd 100644 --- a/price-info/Cargo.toml +++ b/price-info/Cargo.toml @@ -15,5 +15,5 @@ serde_json = "1.0" [dev-dependencies] hyper = "0.11" -parking_lot = "0.5" +parking_lot = "0.6" fake-fetch = { path = "../util/fake-fetch" } diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index b6daa2d407d..c84a1dc5f8d 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -15,7 +15,7 @@ futures-cpupool = "0.1" log = "0.3" multihash ="0.7" order-stat = "0.1" -parking_lot = "0.5" +parking_lot = "0.6" rand = "0.4" rustc-hex = "1.0" semver = "0.9" diff --git a/rpc/src/v1/helpers/mod.rs b/rpc/src/v1/helpers/mod.rs index ce2babd0799..5b62087ab38 100644 --- a/rpc/src/v1/helpers/mod.rs +++ b/rpc/src/v1/helpers/mod.rs @@ -39,7 +39,7 @@ mod subscription_manager; pub use self::dispatch::{Dispatcher, FullDispatcher}; pub use self::network_settings::NetworkSettings; pub use self::poll_manager::PollManager; -pub use self::poll_filter::{PollFilter, limit_logs}; +pub use self::poll_filter::{PollFilter, SyncPollFilter, limit_logs}; pub use self::requests::{ TransactionRequest, FilledTransactionRequest, ConfirmationRequest, ConfirmationPayload, CallRequest, }; diff --git a/rpc/src/v1/helpers/poll_filter.rs b/rpc/src/v1/helpers/poll_filter.rs index a7e42bb4068..19979c814b8 100644 --- a/rpc/src/v1/helpers/poll_filter.rs +++ b/rpc/src/v1/helpers/poll_filter.rs @@ -16,19 +16,41 @@ //! Helper type with all filter state data. -use std::collections::HashSet; +use std::{ + collections::{BTreeSet, HashSet}, + sync::Arc, +}; use ethereum_types::H256; +use parking_lot::Mutex; use v1::types::{Filter, Log}; pub type BlockNumber = u64; +/// Thread-safe filter state. +#[derive(Clone)] +pub struct SyncPollFilter(Arc>); + +impl SyncPollFilter { + /// New `SyncPollFilter` + pub fn new(f: PollFilter) -> Self { + SyncPollFilter(Arc::new(Mutex::new(f))) + } + + /// Modify underlying filter + pub fn modify(&self, f: F) -> R where + F: FnOnce(&mut PollFilter) -> R, + { + f(&mut self.0.lock()) + } +} + /// Filter state. #[derive(Clone)] pub enum PollFilter { /// Number of last block which client was notified about. Block(BlockNumber), - /// Hashes of all transactions which client was notified about. - PendingTransaction(Vec), + /// Hashes of all pending transactions the client knows about. + PendingTransaction(BTreeSet), /// Number of From block number, last seen block hash, pending logs and log filter itself. Logs(BlockNumber, Option, HashSet, Filter) } diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index d33d5e860a4..d20b2feb267 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -167,7 +167,7 @@ impl EthClient Eth for EthClient< } fn block_transaction_count_by_number(&self, num: BlockNumber) -> BoxFuture> { - let block_number = self.client.chain_info().best_block_number; - Box::new(future::ok(match num { BlockNumber::Pending => - self.miner.pending_transactions(block_number).map(|x| x.len().into()), + Some(self.miner.pending_transaction_hashes(&*self.client).len().into()), _ => self.client.block(block_number_to_id(num)).map(|block| block.transactions_count().into()) })) diff --git a/rpc/src/v1/impls/eth_filter.rs b/rpc/src/v1/impls/eth_filter.rs index b79456cd8db..926439cfc91 100644 --- a/rpc/src/v1/impls/eth_filter.rs +++ b/rpc/src/v1/impls/eth_filter.rs @@ -17,7 +17,7 @@ //! Eth Filter RPC implementation use std::sync::Arc; -use std::collections::HashSet; +use std::collections::BTreeSet; use ethcore::miner::{self, MinerService}; use ethcore::filter::Filter as EthcoreFilter; @@ -30,7 +30,7 @@ use jsonrpc_core::futures::{future, Future}; use jsonrpc_core::futures::future::Either; use v1::traits::EthFilter; use v1::types::{BlockNumber, Index, Filter, FilterChanges, Log, H256 as RpcH256, U256 as RpcU256}; -use v1::helpers::{errors, PollFilter, PollManager, limit_logs}; +use v1::helpers::{errors, SyncPollFilter, PollFilter, PollManager, limit_logs}; use v1::impls::eth::pending_logs; /// Something which provides data that can be filtered over. @@ -41,8 +41,8 @@ pub trait Filterable { /// Get a block hash by block id. fn block_hash(&self, id: BlockId) -> Option; - /// pending transaction hashes at the given block. - fn pending_transactions_hashes(&self) -> Vec; + /// pending transaction hashes at the given block (unordered). + fn pending_transaction_hashes(&self) -> BTreeSet; /// Get logs that match the given filter. fn logs(&self, filter: EthcoreFilter) -> BoxFuture>; @@ -51,7 +51,7 @@ pub trait Filterable { fn pending_logs(&self, block_number: u64, filter: &EthcoreFilter) -> Vec; /// Get a reference to the poll manager. - fn polls(&self) -> &Mutex>; + fn polls(&self) -> &Mutex>; /// Get removed logs within route from the given block to the nearest canon block, not including the canon block. Also returns how many logs have been traversed. fn removed_logs(&self, block_hash: H256, filter: &EthcoreFilter) -> (Vec, u64); @@ -61,7 +61,7 @@ pub trait Filterable { pub struct EthFilterClient { client: Arc, miner: Arc, - polls: Mutex>, + polls: Mutex>, } impl EthFilterClient { @@ -87,11 +87,8 @@ impl Filterable for EthFilterClient where self.client.block_hash(id) } - fn pending_transactions_hashes(&self) -> Vec { - self.miner.ready_transactions(&*self.client, usize::max_value(), miner::PendingOrdering::Priority) - .into_iter() - .map(|tx| tx.signed().hash()) - .collect() + fn pending_transaction_hashes(&self) -> BTreeSet { + self.miner.pending_transaction_hashes(&*self.client) } fn logs(&self, filter: EthcoreFilter) -> BoxFuture> { @@ -102,7 +99,7 @@ impl Filterable for EthFilterClient where pending_logs(&*self.miner, block_number, filter) } - fn polls(&self) -> &Mutex> { &self.polls } + fn polls(&self) -> &Mutex> { &self.polls } fn removed_logs(&self, block_hash: H256, filter: &EthcoreFilter) -> (Vec, u64) { let inner = || -> Option> { @@ -143,127 +140,124 @@ impl EthFilter for T { fn new_filter(&self, filter: Filter) -> Result { let mut polls = self.polls().lock(); let block_number = self.best_block_number(); - let id = polls.create_poll(PollFilter::Logs(block_number, None, Default::default(), filter)); + let id = polls.create_poll(SyncPollFilter::new(PollFilter::Logs(block_number, None, Default::default(), filter))); Ok(id.into()) } fn new_block_filter(&self) -> Result { let mut polls = self.polls().lock(); // +1, since we don't want to include the current block - let id = polls.create_poll(PollFilter::Block(self.best_block_number() + 1)); + let id = polls.create_poll(SyncPollFilter::new(PollFilter::Block(self.best_block_number() + 1))); Ok(id.into()) } fn new_pending_transaction_filter(&self) -> Result { let mut polls = self.polls().lock(); - let pending_transactions = self.pending_transactions_hashes(); - let id = polls.create_poll(PollFilter::PendingTransaction(pending_transactions)); + let pending_transactions = self.pending_transaction_hashes(); + let id = polls.create_poll(SyncPollFilter::new(PollFilter::PendingTransaction(pending_transactions))); Ok(id.into()) } fn filter_changes(&self, index: Index) -> BoxFuture { - let mut polls = self.polls().lock(); - Box::new(match polls.poll_mut(&index.value()) { - None => Either::A(future::err(errors::filter_not_found())), - Some(filter) => match *filter { - PollFilter::Block(ref mut block_number) => { - // +1, cause we want to return hashes including current block hash. - let current_number = self.best_block_number() + 1; - let hashes = (*block_number..current_number).into_iter() - .map(BlockId::Number) - .filter_map(|id| self.block_hash(id).map(Into::into)) - .collect::>(); - - *block_number = current_number; - - Either::A(future::ok(FilterChanges::Hashes(hashes))) - }, - PollFilter::PendingTransaction(ref mut previous_hashes) => { - // get hashes of pending transactions - let current_hashes = self.pending_transactions_hashes(); - - let new_hashes = - { - let previous_hashes_set = previous_hashes.iter().collect::>(); - - // find all new hashes - current_hashes - .iter() - .filter(|hash| !previous_hashes_set.contains(hash)) - .cloned() - .map(Into::into) - .collect::>() - }; - - // save all hashes of pending transactions - *previous_hashes = current_hashes; - - // return new hashes - Either::A(future::ok(FilterChanges::Hashes(new_hashes))) - }, - PollFilter::Logs(ref mut block_number, ref mut last_block_hash, ref mut previous_logs, ref filter) => { - // retrive the current block number - let current_number = self.best_block_number(); - - // check if we need to check pending hashes - let include_pending = filter.to_block == Some(BlockNumber::Pending); - - // build appropriate filter - let mut filter: EthcoreFilter = filter.clone().into(); - - // retrieve reorg logs - let (mut reorg, reorg_len) = last_block_hash.map_or_else(|| (Vec::new(), 0), |h| self.removed_logs(h, &filter)); - *block_number -= reorg_len as u64; - - filter.from_block = BlockId::Number(*block_number); - filter.to_block = BlockId::Latest; - - // retrieve pending logs - let pending = if include_pending { - let pending_logs = self.pending_logs(current_number, &filter); - - // remove logs about which client was already notified about - let new_pending_logs: Vec<_> = pending_logs.iter() - .filter(|p| !previous_logs.contains(p)) - .cloned() - .collect(); - - // save all logs retrieved by client - *previous_logs = pending_logs.into_iter().collect(); - - new_pending_logs - } else { - Vec::new() - }; - - // save the number of the next block as a first block from which - // we want to get logs - *block_number = current_number + 1; - - // save the current block hash, which we used to get back to the - // canon chain in case of reorg. - *last_block_hash = self.block_hash(BlockId::Number(current_number)); - - // retrieve logs in range from_block..min(BlockId::Latest..to_block) - let limit = filter.limit; - Either::B(self.logs(filter) - .map(move |logs| { reorg.extend(logs); reorg }) // append reorg logs in the front - .map(move |mut logs| { logs.extend(pending); logs }) // append fetched pending logs - .map(move |logs| limit_logs(logs, limit)) // limit the logs - .map(FilterChanges::Logs)) - } + let filter = match self.polls().lock().poll_mut(&index.value()) { + Some(filter) => filter.clone(), + None => return Box::new(future::err(errors::filter_not_found())), + }; + + Box::new(filter.modify(|filter| match *filter { + PollFilter::Block(ref mut block_number) => { + // +1, cause we want to return hashes including current block hash. + let current_number = self.best_block_number() + 1; + let hashes = (*block_number..current_number).into_iter() + .map(BlockId::Number) + .filter_map(|id| self.block_hash(id).map(Into::into)) + .collect::>(); + + *block_number = current_number; + + Either::A(future::ok(FilterChanges::Hashes(hashes))) + }, + PollFilter::PendingTransaction(ref mut previous_hashes) => { + // get hashes of pending transactions + let current_hashes = self.pending_transaction_hashes(); + + let new_hashes = { + // find all new hashes + current_hashes.difference(previous_hashes) + .cloned() + .map(Into::into) + .collect() + }; + + // save all hashes of pending transactions + *previous_hashes = current_hashes; + + // return new hashes + Either::A(future::ok(FilterChanges::Hashes(new_hashes))) + }, + PollFilter::Logs(ref mut block_number, ref mut last_block_hash, ref mut previous_logs, ref filter) => { + // retrive the current block number + let current_number = self.best_block_number(); + + // check if we need to check pending hashes + let include_pending = filter.to_block == Some(BlockNumber::Pending); + + // build appropriate filter + let mut filter: EthcoreFilter = filter.clone().into(); + + // retrieve reorg logs + let (mut reorg, reorg_len) = last_block_hash.map_or_else(|| (Vec::new(), 0), |h| self.removed_logs(h, &filter)); + *block_number -= reorg_len as u64; + + filter.from_block = BlockId::Number(*block_number); + filter.to_block = BlockId::Latest; + + // retrieve pending logs + let pending = if include_pending { + let pending_logs = self.pending_logs(current_number, &filter); + + // remove logs about which client was already notified about + let new_pending_logs: Vec<_> = pending_logs.iter() + .filter(|p| !previous_logs.contains(p)) + .cloned() + .collect(); + + // save all logs retrieved by client + *previous_logs = pending_logs.into_iter().collect(); + + new_pending_logs + } else { + Vec::new() + }; + + // save the number of the next block as a first block from which + // we want to get logs + *block_number = current_number + 1; + + // save the current block hash, which we used to get back to the + // canon chain in case of reorg. + *last_block_hash = self.block_hash(BlockId::Number(current_number)); + + // retrieve logs in range from_block..min(BlockId::Latest..to_block) + let limit = filter.limit; + Either::B(self.logs(filter) + .map(move |logs| { reorg.extend(logs); reorg }) // append reorg logs in the front + .map(move |mut logs| { logs.extend(pending); logs }) // append fetched pending logs + .map(move |logs| limit_logs(logs, limit)) // limit the logs + .map(FilterChanges::Logs)) } - }) + })) } fn filter_logs(&self, index: Index) -> BoxFuture> { let filter = { let mut polls = self.polls().lock(); - match polls.poll(&index.value()) { - Some(&PollFilter::Logs(ref _block_number, ref _last_block_hash, ref _previous_log, ref filter)) => filter.clone(), - // just empty array - Some(_) => return Box::new(future::ok(Vec::new())), + match polls.poll(&index.value()).and_then(|f| f.modify(|filter| match *filter { + PollFilter::Logs(.., ref filter) => Some(filter.clone()), + _ => None, + })) { + Some(filter) => filter, None => return Box::new(future::err(errors::filter_not_found())), } }; diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index 7c47967b277..e88ac2dab35 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -16,6 +16,7 @@ //! Eth RPC interface for the light client. +use std::collections::BTreeSet; use std::sync::Arc; use jsonrpc_core::{Result, BoxFuture}; @@ -41,7 +42,7 @@ use transaction::SignedTransaction; use v1::impls::eth_filter::Filterable; use v1::helpers::{errors, limit_logs}; -use v1::helpers::{PollFilter, PollManager}; +use v1::helpers::{SyncPollFilter, PollManager}; use v1::helpers::light_fetch::{self, LightFetch}; use v1::traits::Eth; use v1::types::{ @@ -61,7 +62,7 @@ pub struct EthClient { transaction_queue: Arc>, accounts: Arc, cache: Arc>, - polls: Mutex>, + polls: Mutex>, poll_lifetime: u32, gas_price_percentile: usize, } @@ -537,8 +538,8 @@ impl Filterable for EthClient { self.client.block_hash(id) } - fn pending_transactions_hashes(&self) -> Vec<::ethereum_types::H256> { - Vec::new() + fn pending_transaction_hashes(&self) -> BTreeSet<::ethereum_types::H256> { + BTreeSet::new() } fn logs(&self, filter: EthcoreFilter) -> BoxFuture> { @@ -549,7 +550,7 @@ impl Filterable for EthClient { Vec::new() // light clients don't mine. } - fn polls(&self) -> &Mutex> { + fn polls(&self) -> &Mutex> { &self.polls } diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index ce7ffc57a90..fa9f22b2479 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -17,7 +17,7 @@ //! Test implementation of miner service. use std::sync::Arc; -use std::collections::{BTreeMap, HashMap}; +use std::collections::{BTreeMap, BTreeSet, HashMap}; use bytes::Bytes; use ethcore::account_provider::SignError as AccountError; @@ -220,6 +220,10 @@ impl MinerService for TestMinerService { self.queued_transactions() } + fn pending_transaction_hashes(&self, _chain: &C) -> BTreeSet { + self.queued_transactions().into_iter().map(|tx| tx.signed().hash()).collect() + } + fn queued_transactions(&self) -> Vec> { self.pending_transactions.lock().values().cloned().map(|tx| { Arc::new(VerifiedTransaction::from_pending_block_transaction(tx)) diff --git a/rpc_client/Cargo.toml b/rpc_client/Cargo.toml index 81776b3e15d..67efce18cfb 100644 --- a/rpc_client/Cargo.toml +++ b/rpc_client/Cargo.toml @@ -13,7 +13,7 @@ serde = "1.0" serde_json = "1.0" url = "1.2.0" matches = "0.1" -parking_lot = "0.5" +parking_lot = "0.6" jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } jsonrpc-ws-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" } parity-rpc = { path = "../rpc" } diff --git a/scripts/cov.sh b/scripts/cov.sh index 578fc715ce0..b6d25c6921c 100755 --- a/scripts/cov.sh +++ b/scripts/cov.sh @@ -15,18 +15,17 @@ set -x RUSTFLAGS="-C link-dead-code" cargo test --all --no-run || exit $? KCOV_TARGET="target/cov" KCOV_FLAGS="--verify" -EXCLUDE="/usr/lib,/usr/include,$HOME/.cargo,$HOME/.multirust,rocksdb,secp256k1" mkdir -p $KCOV_TARGET echo "Cover RUST" for FILE in `find target/debug/deps ! -name "*.*"` - do - timeout --signal=SIGKILL 5m kcov --exclude-pattern $EXCLUDE $KCOV_FLAGS $KCOV_TARGET $FILE - done -timeout --signal=SIGKILL 5m kcov --exclude-pattern $EXCLUDE $KCOV_FLAGS $KCOV_TARGET target/debug/parity-* +do + timeout --signal=SIGKILL 5m kcov --include-path=$(pwd) --exclude-path=$(pwd)/target $KCOV_FLAGS $KCOV_TARGET $FILE +done +timeout --signal=SIGKILL 5m kcov --include-path=$(pwd) --exclude-path=$(pwd)/target $KCOV_FLAGS $KCOV_TARGET target/debug/parity-* echo "Cover JS" cd js npm install&&npm run test:coverage cd .. bash <(curl -s https://codecov.io/bash)&& -echo "Uploaded code coverage" + echo "Uploaded code coverage" exit 0 diff --git a/secret_store/Cargo.toml b/secret_store/Cargo.toml index a8aed831273..dd419ae4eb9 100644 --- a/secret_store/Cargo.toml +++ b/secret_store/Cargo.toml @@ -8,7 +8,7 @@ authors = ["Parity Technologies "] [dependencies] byteorder = "1.0" log = "0.3" -parking_lot = "0.5" +parking_lot = "0.6" hyper = { version = "0.11", default-features = false } serde = "1.0" serde_json = "1.0" diff --git a/secret_store/src/key_server_cluster/math.rs b/secret_store/src/key_server_cluster/math.rs index 66f26b50869..7fbe48574b1 100644 --- a/secret_store/src/key_server_cluster/math.rs +++ b/secret_store/src/key_server_cluster/math.rs @@ -587,9 +587,13 @@ pub mod tests { let publics: Vec<_> = (0..n).map(|i| public_values_generation(t, &derived_point, &polynoms1[i], &polynoms2[i]).unwrap()).collect(); // keys verification - (0..n).map(|i| (0..n).map(|j| if i != j { - assert!(keys_verification(t, &derived_point, &id_numbers[i], &secrets1[j][i], &secrets2[j][i], &publics[j]).unwrap()); - }).collect::>()).collect::>(); + (0..n).for_each(|i| { + (0..n) + .filter(|&j| i != j) + .for_each(|j| { + assert!(keys_verification(t, &derived_point, &id_numbers[i], &secrets1[j][i], &secrets2[j][i], &publics[j]).unwrap()); + }) + }); // data, generated during keys generation let public_shares: Vec<_> = (0..n).map(|i| compute_public_share(&polynoms1[i][0]).unwrap()).collect(); diff --git a/test.sh b/test.sh index 9e273c7492a..82e05d954c5 100755 --- a/test.sh +++ b/test.sh @@ -42,9 +42,9 @@ echo "________Validate chainspecs________" fi -# Running the C example -echo "________Running the C example________" -cd parity-clib-example && \ +# Running the C++ example +echo "________Running the C++ example________" +cd parity-clib-examples/cpp && \ mkdir -p build && \ cd build && \ cmake .. && \ @@ -52,7 +52,7 @@ cd parity-clib-example && \ ./parity-example && \ cd .. && \ rm -rf build && \ - cd .. + cd ../.. # Running tests echo "________Running Parity Full Test Suite________" diff --git a/transaction-pool/src/pool.rs b/transaction-pool/src/pool.rs index 67da1b1d49c..e2fa36c0e54 100644 --- a/transaction-pool/src/pool.rs +++ b/transaction-pool/src/pool.rs @@ -22,7 +22,7 @@ use error; use listener::{Listener, NoopListener}; use options::Options; use ready::{Ready, Readiness}; -use scoring::{Scoring, ScoreWithRef}; +use scoring::{self, Scoring, ScoreWithRef}; use status::{LightStatus, Status}; use transactions::{AddResult, Transactions}; @@ -139,7 +139,7 @@ impl Pool where ensure!(!self.by_hash.contains_key(transaction.hash()), error::ErrorKind::AlreadyImported(format!("{:?}", transaction.hash()))); self.insertion_id += 1; - let mut transaction = Transaction { + let transaction = Transaction { insertion_id: self.insertion_id, transaction: Arc::new(transaction), }; @@ -148,27 +148,32 @@ impl Pool where // Avoid using should_replace, but rather use scoring for that. { let remove_worst = |s: &mut Self, transaction| { - match s.remove_worst(&transaction) { + match s.remove_worst(transaction) { Err(err) => { - s.listener.rejected(&transaction, err.kind()); + s.listener.rejected(transaction, err.kind()); Err(err) }, - Ok(removed) => { - s.listener.dropped(&removed, Some(&transaction)); + Ok(None) => Ok(false), + Ok(Some(removed)) => { + s.listener.dropped(&removed, Some(transaction)); s.finalize_remove(removed.hash()); - Ok(transaction) + Ok(true) }, } }; while self.by_hash.len() + 1 > self.options.max_count { trace!("Count limit reached: {} > {}", self.by_hash.len() + 1, self.options.max_count); - transaction = remove_worst(self, transaction)?; + if !remove_worst(self, &transaction)? { + break; + } } while self.mem_usage + mem_usage > self.options.max_mem_usage { trace!("Mem limit reached: {} > {}", self.mem_usage + mem_usage, self.options.max_mem_usage); - transaction = remove_worst(self, transaction)?; + if !remove_worst(self, &transaction)? { + break; + } } } @@ -273,28 +278,38 @@ impl Pool where } /// Attempts to remove the worst transaction from the pool if it's worse than the given one. - fn remove_worst(&mut self, transaction: &Transaction) -> error::Result> { + /// + /// Returns `None` in case we couldn't decide if the transaction should replace the worst transaction or not. + /// In such case we will accept the transaction even though it is going to exceed the limit. + fn remove_worst(&mut self, transaction: &Transaction) -> error::Result>> { let to_remove = match self.worst_transactions.iter().next_back() { // No elements to remove? and the pool is still full? None => { warn!("The pool is full but there are no transactions to remove."); return Err(error::ErrorKind::TooCheapToEnter(format!("{:?}", transaction.hash()), "unknown".into()).into()); }, - Some(old) => if self.scoring.should_replace(&old.transaction, transaction) { + Some(old) => match self.scoring.should_replace(&old.transaction, transaction) { + // We can't decide which of them should be removed, so accept both. + scoring::Choice::InsertNew => None, // New transaction is better than the worst one so we can replace it. - old.clone() - } else { + scoring::Choice::ReplaceOld => Some(old.clone()), // otherwise fail - return Err(error::ErrorKind::TooCheapToEnter(format!("{:?}", transaction.hash()), format!("{:?}", old.score)).into()) + scoring::Choice::RejectNew => { + return Err(error::ErrorKind::TooCheapToEnter(format!("{:?}", transaction.hash()), format!("{:?}", old.score)).into()) + }, }, }; - // Remove from transaction set - self.remove_from_set(to_remove.transaction.sender(), |set, scoring| { - set.remove(&to_remove.transaction, scoring) - }); + if let Some(to_remove) = to_remove { + // Remove from transaction set + self.remove_from_set(to_remove.transaction.sender(), |set, scoring| { + set.remove(&to_remove.transaction, scoring) + }); - Ok(to_remove.transaction) + Ok(Some(to_remove.transaction)) + } else { + Ok(None) + } } /// Removes transaction from sender's transaction `HashMap`. @@ -399,6 +414,11 @@ impl Pool where || self.mem_usage >= self.options.max_mem_usage } + /// Returns senders ordered by priority of their transactions. + pub fn senders(&self) -> impl Iterator { + self.best_transactions.iter().map(|tx| tx.transaction.sender()) + } + /// Returns an iterator of pending (ready) transactions. pub fn pending>(&self, ready: R) -> PendingIterator { PendingIterator { diff --git a/transaction-pool/src/scoring.rs b/transaction-pool/src/scoring.rs index 462b7086519..390e016af93 100644 --- a/transaction-pool/src/scoring.rs +++ b/transaction-pool/src/scoring.rs @@ -99,7 +99,9 @@ pub trait Scoring: fmt::Debug { fn update_scores(&self, txs: &[Transaction], scores: &mut [Self::Score], change: Change); /// Decides if `new` should push out `old` transaction from the pool. - fn should_replace(&self, old: &T, new: &T) -> bool; + /// + /// NOTE returning `InsertNew` here can lead to some transactions being accepted above pool limits. + fn should_replace(&self, old: &T, new: &T) -> Choice; } /// A score with a reference to the transaction. diff --git a/transaction-pool/src/tests/helpers.rs b/transaction-pool/src/tests/helpers.rs index b71959b08e9..76a81eb9a00 100644 --- a/transaction-pool/src/tests/helpers.rs +++ b/transaction-pool/src/tests/helpers.rs @@ -22,7 +22,17 @@ use {pool, scoring, Scoring, Ready, Readiness}; use super::Transaction; #[derive(Debug, Default)] -pub struct DummyScoring; +pub struct DummyScoring { + always_insert: bool, +} + +impl DummyScoring { + pub fn always_insert() -> Self { + DummyScoring { + always_insert: true, + } + } +} impl Scoring for DummyScoring { type Score = U256; @@ -58,8 +68,14 @@ impl Scoring for DummyScoring { } } - fn should_replace(&self, old: &Transaction, new: &Transaction) -> bool { - new.gas_price > old.gas_price + fn should_replace(&self, old: &Transaction, new: &Transaction) -> scoring::Choice { + if self.always_insert { + scoring::Choice::InsertNew + } else if new.gas_price > old.gas_price { + scoring::Choice::ReplaceOld + } else { + scoring::Choice::RejectNew + } } } diff --git a/transaction-pool/src/tests/mod.rs b/transaction-pool/src/tests/mod.rs index 808f804cce9..0029d0622f8 100644 --- a/transaction-pool/src/tests/mod.rs +++ b/transaction-pool/src/tests/mod.rs @@ -537,6 +537,60 @@ fn should_return_is_full() { assert!(txq.is_full()); } +#[test] +fn should_import_even_if_limit_is_reached_and_should_replace_returns_insert_new() { + // given + let b = TransactionBuilder::default(); + let mut txq = TestPool::with_scoring(DummyScoring::always_insert(), Options { + max_count: 1, + ..Default::default() + }); + txq.import(b.tx().nonce(0).gas_price(5).new()).unwrap(); + assert_eq!(txq.light_status(), LightStatus { + transaction_count: 1, + senders: 1, + mem_usage: 0, + }); + + // when + txq.import(b.tx().nonce(1).gas_price(5).new()).unwrap(); + + // then + assert_eq!(txq.light_status(), LightStatus { + transaction_count: 2, + senders: 1, + mem_usage: 0, + }); +} + +#[test] +fn should_not_import_even_if_limit_is_reached_and_should_replace_returns_false() { + // given + let b = TransactionBuilder::default(); + let mut txq = TestPool::with_scoring(DummyScoring::default(), Options { + max_count: 1, + ..Default::default() + }); + txq.import(b.tx().nonce(0).gas_price(5).new()).unwrap(); + assert_eq!(txq.light_status(), LightStatus { + transaction_count: 1, + senders: 1, + mem_usage: 0, + }); + + // when + let err = txq.import(b.tx().nonce(1).gas_price(5).new()).unwrap_err(); + + // then + assert_eq!(err.kind(), + &error::ErrorKind::TooCheapToEnter("0x00000000000000000000000000000000000000000000000000000000000001f5".into(), "0x5".into())); + assert_eq!(txq.light_status(), LightStatus { + transaction_count: 1, + senders: 1, + mem_usage: 0, + }); +} + mod listener { use std::cell::RefCell; use std::rc::Rc; @@ -577,7 +631,7 @@ mod listener { let b = TransactionBuilder::default(); let listener = MyListener::default(); let results = listener.0.clone(); - let mut txq = Pool::new(listener, DummyScoring, Options { + let mut txq = Pool::new(listener, DummyScoring::default(), Options { max_per_sender: 1, max_count: 2, ..Default::default() @@ -615,7 +669,7 @@ mod listener { let b = TransactionBuilder::default(); let listener = MyListener::default(); let results = listener.0.clone(); - let mut txq = Pool::new(listener, DummyScoring, Options::default()); + let mut txq = Pool::new(listener, DummyScoring::default(), Options::default()); // insert let tx1 = txq.import(b.tx().nonce(1).new()).unwrap(); @@ -634,7 +688,7 @@ mod listener { let b = TransactionBuilder::default(); let listener = MyListener::default(); let results = listener.0.clone(); - let mut txq = Pool::new(listener, DummyScoring, Options::default()); + let mut txq = Pool::new(listener, DummyScoring::default(), Options::default()); // insert txq.import(b.tx().nonce(1).new()).unwrap(); @@ -652,7 +706,7 @@ mod listener { let b = TransactionBuilder::default(); let listener = MyListener::default(); let results = listener.0.clone(); - let mut txq = Pool::new(listener, DummyScoring, Options::default()); + let mut txq = Pool::new(listener, DummyScoring::default(), Options::default()); // insert txq.import(b.tx().nonce(1).new()).unwrap(); diff --git a/updater/Cargo.toml b/updater/Cargo.toml index 8d94680335c..1bd8736bd7d 100644 --- a/updater/Cargo.toml +++ b/updater/Cargo.toml @@ -18,7 +18,7 @@ ethcore = { path = "../ethcore" } ethcore-bytes = { path = "../util/bytes" } ethcore-sync = { path = "../ethcore/sync" } ethereum-types = "0.3" -parking_lot = "0.5" +parking_lot = "0.6" parity-hash-fetch = { path = "../hash-fetch" } parity-version = { path = "../util/version" } path = { path = "../util/path" } diff --git a/util/blooms-db/Cargo.toml b/util/blooms-db/Cargo.toml index da6bb154c57..23048a7d571 100644 --- a/util/blooms-db/Cargo.toml +++ b/util/blooms-db/Cargo.toml @@ -7,7 +7,7 @@ authors = ["Parity Technologies "] [dependencies] byteorder = "1.2" ethbloom = "0.5" -parking_lot = "0.5.4" +parking_lot = "0.6" tiny-keccak = "1.4" [dev-dependencies] diff --git a/util/dir/Cargo.toml b/util/dir/Cargo.toml index e1a13401a25..bdaea99109e 100644 --- a/util/dir/Cargo.toml +++ b/util/dir/Cargo.toml @@ -1,9 +1,11 @@ [package] name = "dir" -version = "0.1.0" +version = "0.1.1" authors = ["Parity Technologies "] +license = "GPL3" [dependencies] ethereum-types = "0.3" journaldb = { path = "../journaldb" } app_dirs = { git = "https://github.com/paritytech/app-dirs-rs" } +dirs = "1.0.2" diff --git a/util/dir/src/helpers.rs b/util/dir/src/helpers.rs index 820b9dc5af6..8e703206b73 100644 --- a/util/dir/src/helpers.rs +++ b/util/dir/src/helpers.rs @@ -15,12 +15,11 @@ // along with Parity. If not, see . //! Directory helper functions -use std::env; /// Replaces `$HOME` str with home directory path. pub fn replace_home(base: &str, arg: &str) -> String { // the $HOME directory on mac os should be `~/Library` or `~/Library/Application Support` - let r = arg.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()); + let r = arg.replace("$HOME", ::dirs::home_dir().unwrap().to_str().unwrap()); let r = r.replace("$BASE", base); r.replace("/", &::std::path::MAIN_SEPARATOR.to_string()) } diff --git a/util/dir/src/lib.rs b/util/dir/src/lib.rs index 7404a2cbcab..712b53f0de3 100644 --- a/util/dir/src/lib.rs +++ b/util/dir/src/lib.rs @@ -18,11 +18,12 @@ //! Dir utilities for platform-specific operations extern crate app_dirs; +extern crate dirs; extern crate ethereum_types; extern crate journaldb; pub mod helpers; -use std::{env, fs}; +use std::fs; use std::path::{PathBuf, Path}; use ethereum_types::{H64, H256}; use journaldb::Algorithm; @@ -31,19 +32,21 @@ use app_dirs::{AppInfo, get_app_root, AppDataType}; // re-export platform-specific functions use platform::*; +pub use dirs::home_dir; + /// Platform-specific chains path - Windows only -#[cfg(target_os = "windows")] pub const CHAINS_PATH: &'static str = "$LOCAL/chains"; +#[cfg(target_os = "windows")] pub const CHAINS_PATH: &str = "$LOCAL/chains"; /// Platform-specific chains path -#[cfg(not(target_os = "windows"))] pub const CHAINS_PATH: &'static str = "$BASE/chains"; +#[cfg(not(target_os = "windows"))] pub const CHAINS_PATH: &str = "$BASE/chains"; /// Platform-specific cache path - Windows only -#[cfg(target_os = "windows")] pub const CACHE_PATH: &'static str = "$LOCAL/cache"; +#[cfg(target_os = "windows")] pub const CACHE_PATH: &str = "$LOCAL/cache"; /// Platform-specific cache path -#[cfg(not(target_os = "windows"))] pub const CACHE_PATH: &'static str = "$BASE/cache"; +#[cfg(not(target_os = "windows"))] pub const CACHE_PATH: &str = "$BASE/cache"; // this const is irrelevent cause we do have migrations now, // but we still use it for backwards compatibility -const LEGACY_CLIENT_DB_VER_STR: &'static str = "5.3"; +const LEGACY_CLIENT_DB_VER_STR: &str = "5.3"; #[derive(Debug, PartialEq)] /// Parity local data directories @@ -239,7 +242,7 @@ pub fn default_hypervisor_path() -> PathBuf { /// Get home directory. fn home() -> PathBuf { - env::home_dir().expect("Failed to get home dir") + dirs::home_dir().expect("Failed to get home dir") } /// Geth path @@ -312,9 +315,9 @@ mod platform { #[cfg(not(any(target_os = "macos", windows)))] mod platform { use std::path::PathBuf; - pub const AUTHOR: &'static str = "parity"; - pub const PRODUCT: &'static str = "io.parity.ethereum"; - pub const PRODUCT_HYPERVISOR: &'static str = "io.parity.ethereum-updates"; + pub const AUTHOR: &str = "parity"; + pub const PRODUCT: &str = "io.parity.ethereum"; + pub const PRODUCT_HYPERVISOR: &str = "io.parity.ethereum-updates"; pub fn parity_base() -> PathBuf { let mut home = super::home(); diff --git a/util/error/Cargo.toml b/util/error/Cargo.toml deleted file mode 100644 index 66901f16991..00000000000 --- a/util/error/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "util-error" -version = "0.1.0" -authors = ["Parity Technologies "] - -[dependencies] -rlp = { path = "../rlp" } -ethereum-types = "0.3" -error-chain = { version = "0.12", default-features = false } -rustc-hex = "1.0" diff --git a/util/error/src/lib.rs b/util/error/src/lib.rs deleted file mode 100644 index 86b8f44393b..00000000000 --- a/util/error/src/lib.rs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! General error types for use in ethcore. - -#![allow(missing_docs)] -#![allow(unknown_lints)] - -#[macro_use] -extern crate error_chain; - -extern crate ethereum_types; -extern crate rlp; -extern crate rustc_hex; - -use std::fmt; -use rustc_hex::FromHexError; -use rlp::DecoderError; -use ethereum_types::H256; - -#[derive(Debug)] -/// Error in database subsystem. -pub enum BaseDataError { - /// An entry was removed more times than inserted. - NegativelyReferencedHash(H256), - /// A committed value was inserted more than once. - AlreadyExists(H256), -} - -impl fmt::Display for BaseDataError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - BaseDataError::NegativelyReferencedHash(hash) => - write!(f, "Entry {} removed from database more times than it was added.", hash), - BaseDataError::AlreadyExists(hash) => - write!(f, "Committed key already exists in database: {}", hash), - } - } -} - -impl std::error::Error for BaseDataError { - fn description(&self) -> &str { - "Error in database subsystem" - } -} - -error_chain! { - types { - UtilError, ErrorKind, ResultExt, Result; - } - - foreign_links { - Io(::std::io::Error); - FromHex(FromHexError); - Decoder(DecoderError); - BaseData(BaseDataError); - } -} diff --git a/util/fetch/Cargo.toml b/util/fetch/Cargo.toml index 98b1fc58234..8f87c6c0f93 100644 --- a/util/fetch/Cargo.toml +++ b/util/fetch/Cargo.toml @@ -8,11 +8,11 @@ authors = ["Parity Technologies "] [dependencies] futures = "0.1" -futures-timer = "0.1" hyper = "0.11" hyper-rustls = "0.11" log = "0.4" tokio-core = "0.1" +tokio-timer = "0.1" url = "1" bytes = "0.4" diff --git a/util/fetch/src/client.rs b/util/fetch/src/client.rs index cda802cfb0c..03a3a5a2c00 100644 --- a/util/fetch/src/client.rs +++ b/util/fetch/src/client.rs @@ -17,7 +17,6 @@ use futures::future::{self, Loop}; use futures::sync::{mpsc, oneshot}; use futures::{self, Future, Async, Sink, Stream}; -use futures_timer::FutureExt; use hyper::header::{UserAgent, Location, ContentLength, ContentType}; use hyper::mime::Mime; use hyper::{self, Method, StatusCode}; @@ -31,6 +30,7 @@ use std::thread; use std::time::Duration; use std::{io, fmt}; use tokio_core::reactor; +use tokio_timer::{self, Timer}; use url::{self, Url}; use bytes::Bytes; @@ -142,6 +142,7 @@ type ChanItem = Option<(Request, Abort, TxResponse)>; pub struct Client { core: mpsc::Sender, refs: Arc, + timer: Timer, } // When cloning a client we increment the internal reference counter. @@ -151,6 +152,7 @@ impl Clone for Client { Client { core: self.core.clone(), refs: self.refs.clone(), + timer: self.timer.clone(), } } } @@ -193,6 +195,7 @@ impl Client { Ok(Client { core: tx_proto, refs: Arc::new(AtomicUsize::new(1)), + timer: Timer::default(), }) } @@ -286,17 +289,9 @@ impl Fetch for Client { Error::BackgroundThreadDead }) .and_then(|_| rx_res.map_err(|oneshot::Canceled| Error::BackgroundThreadDead)) - .and_then(future::result) - .timeout(maxdur) - .map_err(|err| { - if let Error::Io(ref e) = err { - if let io::ErrorKind::TimedOut = e.kind() { - return Error::Timeout - } - } - err.into() - }); - Box::new(future) + .and_then(future::result); + + Box::new(self.timer.timeout(future, maxdur)) } /// Get content from some URL. @@ -575,6 +570,8 @@ pub enum Error { Aborted, /// Too many redirects have been encountered. TooManyRedirects, + /// tokio-timer gave us an error. + Timer(tokio_timer::TimerError), /// The maximum duration was reached. Timeout, /// The response body is too large. @@ -592,6 +589,7 @@ impl fmt::Display for Error { Error::Io(ref e) => write!(fmt, "{}", e), Error::BackgroundThreadDead => write!(fmt, "background thread gond"), Error::TooManyRedirects => write!(fmt, "too many redirects"), + Error::Timer(ref e) => write!(fmt, "{}", e), Error::Timeout => write!(fmt, "request timed out"), Error::SizeLimit => write!(fmt, "size limit reached"), } @@ -616,14 +614,23 @@ impl From for Error { } } +impl From> for Error { + fn from(e: tokio_timer::TimeoutError) -> Self { + match e { + tokio_timer::TimeoutError::Timer(_, e) => Error::Timer(e), + tokio_timer::TimeoutError::TimedOut(_) => Error::Timeout, + } + } +} + #[cfg(test)] mod test { use super::*; use futures::future; use futures::sync::mpsc; - use futures_timer::Delay; use hyper::StatusCode; use hyper::server::{Http, Request, Response, Service}; + use tokio_timer::Timer; use std; use std::io::Read; use std::net::SocketAddr; @@ -720,7 +727,7 @@ mod test { } } - struct TestServer; + struct TestServer(Timer); impl Service for TestServer { type Request = Request; @@ -750,7 +757,10 @@ mod test { } "/delay" => { let d = Duration::from_secs(req.uri().query().unwrap_or("0").parse().unwrap()); - Box::new(Delay::new(d).from_err().map(|_| Response::new())) + Box::new(self.0.sleep(d) + .map_err(|_| return io::Error::new(io::ErrorKind::Other, "timer error")) + .from_err() + .map(|_| Response::new())) } _ => Box::new(future::ok(Response::new().with_status(StatusCode::NotFound))) } @@ -764,7 +774,7 @@ mod test { let rx_end_fut = rx_end.into_future().map(|_| ()).map_err(|_| ()); thread::spawn(move || { let addr = ADDRESS.parse().unwrap(); - let server = Http::new().bind(&addr, || Ok(TestServer)).unwrap(); + let server = Http::new().bind(&addr, || Ok(TestServer(Timer::default()))).unwrap(); tx_start.send(server.local_addr().unwrap()).unwrap_or(()); server.run_until(rx_end_fut).unwrap(); }); diff --git a/util/fetch/src/lib.rs b/util/fetch/src/lib.rs index 8e50fa5e6a5..37225dfa1a4 100644 --- a/util/fetch/src/lib.rs +++ b/util/fetch/src/lib.rs @@ -23,12 +23,12 @@ extern crate log; #[macro_use] extern crate futures; -extern crate futures_timer; extern crate hyper; extern crate hyper_rustls; extern crate tokio_core; +extern crate tokio_timer; extern crate url; extern crate bytes; diff --git a/util/hashdb/Cargo.toml b/util/hashdb/Cargo.toml index d4e055f9ff0..f5e63fb1ba5 100644 --- a/util/hashdb/Cargo.toml +++ b/util/hashdb/Cargo.toml @@ -1,10 +1,10 @@ [package] name = "hashdb" -version = "0.1.1" +version = "0.2.0" authors = ["Parity Technologies "] description = "trait for hash-keyed databases." license = "GPL-3.0" [dependencies] elastic-array = "0.10" -ethereum-types = "0.3" +heapsize = "0.4" \ No newline at end of file diff --git a/util/hashdb/src/lib.rs b/util/hashdb/src/lib.rs index 182e81c5dc0..4f5bed48c41 100644 --- a/util/hashdb/src/lib.rs +++ b/util/hashdb/src/lib.rs @@ -14,65 +14,70 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! Database of byte-slices keyed to their Keccak hash. +//! Database of byte-slices keyed to their hash. extern crate elastic_array; -extern crate ethereum_types; +extern crate heapsize; -use std::collections::HashMap; use elastic_array::ElasticArray128; -use ethereum_types::H256; +use heapsize::HeapSizeOf; +use std::collections::HashMap; +use std::{fmt::Debug, hash::Hash}; + +/// Trait describing an object that can hash a slice of bytes. Used to abstract +/// other types over the hashing algorithm. Defines a single `hash` method and an +/// `Out` associated type with the necessary bounds. +pub trait Hasher: Sync + Send { + /// The output type of the `Hasher` + type Out: AsRef<[u8]> + AsMut<[u8]> + Default + HeapSizeOf + Debug + PartialEq + Eq + Hash + Send + Sync + Clone + Copy; + /// What to use to build `HashMap`s with this `Hasher` + type StdHasher: Sync + Send + Default + std::hash::Hasher; + /// The length in bytes of the `Hasher` output + const LENGTH: usize; + + /// Compute the hash of the provided slice of bytes returning the `Out` type of the `Hasher` + fn hash(x: &[u8]) -> Self::Out; +} /// `HashDB` value type. pub type DBValue = ElasticArray128; -/// Trait modelling datastore keyed by a 32-byte Keccak hash. -pub trait HashDB: AsHashDB + Send + Sync { +/// Trait modelling datastore keyed by a hash defined by the `Hasher`. +pub trait HashDB: Send + Sync + AsHashDB { /// Get the keys in the database together with number of underlying references. - fn keys(&self) -> HashMap; + fn keys(&self) -> HashMap; /// Look up a given hash into the bytes that hash to it, returning None if the /// hash is not known. - fn get(&self, key: &H256) -> Option; + fn get(&self, key: &H::Out) -> Option; /// Check for the existance of a hash-key. - fn contains(&self, key: &H256) -> bool; + fn contains(&self, key: &H::Out) -> bool; /// Insert a datum item into the DB and return the datum's hash for a later lookup. Insertions /// are counted and the equivalent number of `remove()`s must be performed before the data /// is considered dead. - fn insert(&mut self, value: &[u8]) -> H256; + fn insert(&mut self, value: &[u8]) -> H::Out; - /// Like `insert()` , except you provide the key and the data is all moved. - fn emplace(&mut self, key: H256, value: DBValue); + /// Like `insert()`, except you provide the key and the data is all moved. + fn emplace(&mut self, key: H::Out, value: DBValue); /// Remove a datum previously inserted. Insertions can be "owed" such that the same number of `insert()`s may /// happen without the data being eventually being inserted into the DB. It can be "owed" more than once. - fn remove(&mut self, key: &H256); + fn remove(&mut self, key: &H::Out); } /// Upcast trait. -pub trait AsHashDB { +pub trait AsHashDB { /// Perform upcast to HashDB for anything that derives from HashDB. - fn as_hashdb(&self) -> &HashDB; + fn as_hashdb(&self) -> &HashDB; /// Perform mutable upcast to HashDB for anything that derives from HashDB. - fn as_hashdb_mut(&mut self) -> &mut HashDB; + fn as_hashdb_mut(&mut self) -> &mut HashDB; } -impl AsHashDB for T { - fn as_hashdb(&self) -> &HashDB { - self - } - fn as_hashdb_mut(&mut self) -> &mut HashDB { - self - } +// NOTE: There used to be a `impl AsHashDB for T` but that does not work with generics. See https://stackoverflow.com/questions/48432842/implementing-a-trait-for-reference-and-non-reference-types-causes-conflicting-im +// This means we need concrete impls of AsHashDB in several places, which somewhat defeats the point of the trait. +impl<'a, H: Hasher> AsHashDB for &'a mut HashDB { + fn as_hashdb(&self) -> &HashDB { &**self } + fn as_hashdb_mut(&mut self) -> &mut HashDB { &mut **self } } -impl<'a> AsHashDB for &'a mut HashDB { - fn as_hashdb(&self) -> &HashDB { - &**self - } - - fn as_hashdb_mut(&mut self) -> &mut HashDB { - &mut **self - } -} diff --git a/util/io/Cargo.toml b/util/io/Cargo.toml index 71688661605..0e1dfbbc10a 100644 --- a/util/io/Cargo.toml +++ b/util/io/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Parity Technologies "] fnv = "1.0" mio = { version = "0.6.8", optional = true } crossbeam = "0.3" -parking_lot = "0.5" +parking_lot = "0.6" log = "0.3" slab = "0.4" num_cpus = "1.8" diff --git a/util/journaldb/Cargo.toml b/util/journaldb/Cargo.toml index dea70bd6a43..bd6c83415bc 100644 --- a/util/journaldb/Cargo.toml +++ b/util/journaldb/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "journaldb" -version = "0.1.0" +version = "0.2.0" authors = ["Parity Technologies "] description = "A `HashDB` which can manage a short-term journal potentially containing many forks of mutually exclusive actions" license = "GPL3" @@ -8,15 +8,15 @@ license = "GPL3" [dependencies] ethcore-bytes = { path = "../bytes" } ethereum-types = "0.3" -hashdb = { path = "../hashdb" } +hashdb = { version = "0.2.0", path = "../hashdb" } heapsize = "0.4" +keccak-hasher = { path = "../keccak-hasher" } kvdb = { path = "../kvdb" } log = "0.3" -memorydb = { path = "../memorydb" } -parking_lot = "0.5" +memorydb = { version = "0.2.0", path = "../memorydb" } +parking_lot = "0.6" plain_hasher = { path = "../plain_hasher" } rlp = { path = "../rlp" } -util-error = { path = "../error" } [dev-dependencies] ethcore-logger = { path = "../../logger" } diff --git a/util/journaldb/src/archivedb.rs b/util/journaldb/src/archivedb.rs index e2d8c800709..3993887e470 100644 --- a/util/journaldb/src/archivedb.rs +++ b/util/journaldb/src/archivedb.rs @@ -18,16 +18,18 @@ use std::collections::HashMap; use std::collections::hash_map::Entry; +use std::io; use std::sync::Arc; -use rlp::{encode, decode}; + +use bytes::Bytes; +use ethereum_types::H256; use hashdb::*; +use keccak_hasher::KeccakHasher; +use kvdb::{KeyValueDB, DBTransaction}; +use rlp::{encode, decode}; +use super::{DB_PREFIX_LEN, LATEST_ERA_KEY, error_key_already_exists, error_negatively_reference_hash}; use super::memorydb::*; -use super::{DB_PREFIX_LEN, LATEST_ERA_KEY}; use traits::JournalDB; -use kvdb::{KeyValueDB, DBTransaction}; -use ethereum_types::H256; -use error::{BaseDataError, UtilError}; -use bytes::Bytes; /// Implementation of the `HashDB` trait for a disk-backed database with a memory overlay /// and latent-removal semantics. @@ -37,7 +39,7 @@ use bytes::Bytes; /// immediately. As this is an "archive" database, nothing is ever removed. This means /// that the states of any block the node has ever processed will be accessible. pub struct ArchiveDB { - overlay: MemoryDB, + overlay: MemoryDB, backing: Arc, latest_era: Option, column: Option, @@ -62,7 +64,7 @@ impl ArchiveDB { } } -impl HashDB for ArchiveDB { +impl HashDB for ArchiveDB { fn keys(&self) -> HashMap { let mut ret: HashMap = self.backing.iter(self.column) .map(|(key, _)| (H256::from_slice(&*key), 1)) @@ -125,7 +127,7 @@ impl JournalDB for ArchiveDB { self.latest_era.is_none() } - fn journal_under(&mut self, batch: &mut DBTransaction, now: u64, _id: &H256) -> Result { + fn journal_under(&mut self, batch: &mut DBTransaction, now: u64, _id: &H256) -> io::Result { let mut inserts = 0usize; let mut deletes = 0usize; @@ -148,12 +150,12 @@ impl JournalDB for ArchiveDB { Ok((inserts + deletes) as u32) } - fn mark_canonical(&mut self, _batch: &mut DBTransaction, _end_era: u64, _canon_id: &H256) -> Result { + fn mark_canonical(&mut self, _batch: &mut DBTransaction, _end_era: u64, _canon_id: &H256) -> io::Result { // keep everything! it's an archive, after all. Ok(0) } - fn inject(&mut self, batch: &mut DBTransaction) -> Result { + fn inject(&mut self, batch: &mut DBTransaction) -> io::Result { let mut inserts = 0usize; let mut deletes = 0usize; @@ -161,7 +163,7 @@ impl JournalDB for ArchiveDB { let (key, (value, rc)) = i; if rc > 0 { if self.backing.get(self.column, &key)?.is_some() { - return Err(BaseDataError::AlreadyExists(key).into()); + return Err(error_key_already_exists(&key)); } batch.put(self.column, &key, &value); inserts += 1; @@ -169,7 +171,7 @@ impl JournalDB for ArchiveDB { if rc < 0 { assert!(rc == -1); if self.backing.get(self.column, &key)?.is_none() { - return Err(BaseDataError::NegativelyReferencedHash(key).into()); + return Err(error_negatively_reference_hash(&key)); } batch.delete(self.column, &key); deletes += 1; @@ -191,7 +193,7 @@ impl JournalDB for ArchiveDB { &self.backing } - fn consolidate(&mut self, with: MemoryDB) { + fn consolidate(&mut self, with: MemoryDB) { self.overlay.consolidate(with); } } diff --git a/util/journaldb/src/as_hash_db_impls.rs b/util/journaldb/src/as_hash_db_impls.rs new file mode 100644 index 00000000000..bd3b0e2d76f --- /dev/null +++ b/util/journaldb/src/as_hash_db_impls.rs @@ -0,0 +1,49 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Impls of the `AsHashDB` upcast trait for all different variants of DB +use hashdb::{HashDB, AsHashDB}; +use keccak_hasher::KeccakHasher; +use archivedb::ArchiveDB; +use earlymergedb::EarlyMergeDB; +use overlayrecentdb::OverlayRecentDB; +use refcounteddb::RefCountedDB; +use overlaydb::OverlayDB; + +impl AsHashDB for ArchiveDB { + fn as_hashdb(&self) -> &HashDB { self } + fn as_hashdb_mut(&mut self) -> &mut HashDB { self } +} + +impl AsHashDB for EarlyMergeDB { + fn as_hashdb(&self) -> &HashDB { self } + fn as_hashdb_mut(&mut self) -> &mut HashDB { self } +} + +impl AsHashDB for OverlayRecentDB { + fn as_hashdb(&self) -> &HashDB { self } + fn as_hashdb_mut(&mut self) -> &mut HashDB { self } +} + +impl AsHashDB for RefCountedDB { + fn as_hashdb(&self) -> &HashDB { self } + fn as_hashdb_mut(&mut self) -> &mut HashDB { self } +} + +impl AsHashDB for OverlayDB { + fn as_hashdb(&self) -> &HashDB { self } + fn as_hashdb_mut(&mut self) -> &mut HashDB { self } +} \ No newline at end of file diff --git a/util/journaldb/src/earlymergedb.rs b/util/journaldb/src/earlymergedb.rs index 25e078bdae1..68b8675af58 100644 --- a/util/journaldb/src/earlymergedb.rs +++ b/util/journaldb/src/earlymergedb.rs @@ -18,18 +18,20 @@ use std::collections::HashMap; use std::collections::hash_map::Entry; +use std::io; use std::sync::Arc; -use parking_lot::RwLock; -use heapsize::HeapSizeOf; -use rlp::{encode, decode}; + +use bytes::Bytes; +use ethereum_types::H256; use hashdb::*; +use heapsize::HeapSizeOf; +use keccak_hasher::KeccakHasher; +use kvdb::{KeyValueDB, DBTransaction}; use memorydb::*; -use super::{DB_PREFIX_LEN, LATEST_ERA_KEY}; +use parking_lot::RwLock; +use rlp::{encode, decode}; +use super::{DB_PREFIX_LEN, LATEST_ERA_KEY, error_negatively_reference_hash, error_key_already_exists}; use super::traits::JournalDB; -use kvdb::{KeyValueDB, DBTransaction}; -use ethereum_types::H256; -use error::{BaseDataError, UtilError}; -use bytes::Bytes; use util::{DatabaseKey, DatabaseValueView, DatabaseValueRef}; #[derive(Debug, Clone, PartialEq, Eq)] @@ -105,7 +107,7 @@ enum RemoveFrom { /// /// TODO: `store_reclaim_period` pub struct EarlyMergeDB { - overlay: MemoryDB, + overlay: MemoryDB, backing: Arc, refs: Option>>>, latest_era: Option, @@ -285,7 +287,7 @@ impl EarlyMergeDB { } } -impl HashDB for EarlyMergeDB { +impl HashDB for EarlyMergeDB { fn keys(&self) -> HashMap { let mut ret: HashMap = self.backing.iter(self.column) .map(|(key, _)| (H256::from_slice(&*key), 1)) @@ -360,7 +362,7 @@ impl JournalDB for EarlyMergeDB { self.backing.get_by_prefix(self.column, &id[0..DB_PREFIX_LEN]).map(|b| b.into_vec()) } - fn journal_under(&mut self, batch: &mut DBTransaction, now: u64, id: &H256) -> Result { + fn journal_under(&mut self, batch: &mut DBTransaction, now: u64, id: &H256) -> io::Result { // record new commit's details. let mut refs = match self.refs.as_ref() { Some(refs) => refs.write(), @@ -424,7 +426,7 @@ impl JournalDB for EarlyMergeDB { } } - fn mark_canonical(&mut self, batch: &mut DBTransaction, end_era: u64, canon_id: &H256) -> Result { + fn mark_canonical(&mut self, batch: &mut DBTransaction, end_era: u64, canon_id: &H256) -> io::Result { let mut refs = self.refs.as_ref().unwrap().write(); // apply old commits' details @@ -486,7 +488,7 @@ impl JournalDB for EarlyMergeDB { Ok(0) } - fn inject(&mut self, batch: &mut DBTransaction) -> Result { + fn inject(&mut self, batch: &mut DBTransaction) -> io::Result { let mut ops = 0; for (key, (value, rc)) in self.overlay.drain() { if rc != 0 { ops += 1 } @@ -495,13 +497,13 @@ impl JournalDB for EarlyMergeDB { 0 => {} 1 => { if self.backing.get(self.column, &key)?.is_some() { - return Err(BaseDataError::AlreadyExists(key).into()); + return Err(error_key_already_exists(&key)); } batch.put(self.column, &key, &value) } -1 => { if self.backing.get(self.column, &key)?.is_none() { - return Err(BaseDataError::NegativelyReferencedHash(key).into()); + return Err(error_negatively_reference_hash(&key)); } batch.delete(self.column, &key) } @@ -512,7 +514,7 @@ impl JournalDB for EarlyMergeDB { Ok(ops) } - fn consolidate(&mut self, with: MemoryDB) { + fn consolidate(&mut self, with: MemoryDB) { self.overlay.consolidate(with); } } diff --git a/util/journaldb/src/lib.rs b/util/journaldb/src/lib.rs index 7607271c8d2..5b2381f2dd8 100644 --- a/util/journaldb/src/lib.rs +++ b/util/journaldb/src/lib.rs @@ -23,12 +23,12 @@ extern crate log; extern crate ethereum_types; extern crate ethcore_bytes as bytes; extern crate hashdb; +extern crate keccak_hasher; extern crate kvdb; extern crate memorydb; extern crate parking_lot; extern crate plain_hasher; extern crate rlp; -extern crate util_error as error; #[cfg(test)] extern crate ethcore_logger; @@ -37,7 +37,7 @@ extern crate keccak_hash as keccak; #[cfg(test)] extern crate kvdb_memorydb; -use std::{fmt, str}; +use std::{fmt, str, io}; use std::sync::Arc; /// Export the journaldb module. @@ -47,6 +47,7 @@ mod earlymergedb; mod overlayrecentdb; mod refcounteddb; mod util; +mod as_hash_db_impls; pub mod overlaydb; @@ -80,10 +81,6 @@ pub enum Algorithm { RefCounted, } -impl Default for Algorithm { - fn default() -> Algorithm { Algorithm::OverlayRecent } -} - impl str::FromStr for Algorithm { type Err = String; @@ -153,6 +150,14 @@ pub fn new(backing: Arc<::kvdb::KeyValueDB>, algorithm: Algorithm, col: Option io::Error { + io::Error::new(io::ErrorKind::AlreadyExists, hash.to_string()) +} + +fn error_negatively_reference_hash(hash: ðereum_types::H256) -> io::Error { + io::Error::new(io::ErrorKind::Other, format!("Entry {} removed from database more times than it was added.", hash)) +} + #[cfg(test)] mod tests { use super::Algorithm; @@ -181,11 +186,6 @@ mod tests { assert!(!Algorithm::RefCounted.is_stable()); } - #[test] - fn test_journal_algorithm_default() { - assert_eq!(Algorithm::default(), Algorithm::OverlayRecent); - } - #[test] fn test_journal_algorithm_all_types() { // compiling should fail if some cases are not covered diff --git a/util/journaldb/src/overlaydb.rs b/util/journaldb/src/overlaydb.rs index 46bf42c0ad5..f4b20b2193b 100644 --- a/util/journaldb/src/overlaydb.rs +++ b/util/journaldb/src/overlaydb.rs @@ -16,15 +16,18 @@ //! Disk-backed `HashDB` implementation. -use std::sync::Arc; use std::collections::HashMap; use std::collections::hash_map::Entry; -use error::{Result, BaseDataError}; +use std::io; +use std::sync::Arc; + use ethereum_types::H256; use rlp::{Rlp, RlpStream, Encodable, DecoderError, Decodable, encode, decode}; use hashdb::*; +use keccak_hasher::KeccakHasher; use memorydb::*; use kvdb::{KeyValueDB, DBTransaction}; +use super::error_negatively_reference_hash; /// Implementation of the `HashDB` trait for a disk-backed database with a memory overlay. /// @@ -36,7 +39,7 @@ use kvdb::{KeyValueDB, DBTransaction}; /// queries have an immediate effect in terms of these functions. #[derive(Clone)] pub struct OverlayDB { - overlay: MemoryDB, + overlay: MemoryDB, backing: Arc, column: Option, } @@ -64,7 +67,7 @@ impl Encodable for Payload { } impl Decodable for Payload { - fn decode(rlp: &Rlp) -> ::std::result::Result { + fn decode(rlp: &Rlp) -> Result { let payload = Payload { count: rlp.val_at(0)?, value: DBValue::from_slice(rlp.at(1)?.data()?), @@ -89,14 +92,14 @@ impl OverlayDB { /// Commit all operations in a single batch. #[cfg(test)] - pub fn commit(&mut self) -> Result { + pub fn commit(&mut self) -> io::Result { let mut batch = self.backing.transaction(); let res = self.commit_to_batch(&mut batch)?; self.backing.write(batch).map(|_| res).map_err(|e| e.into()) } /// Commit all operations to given batch. - pub fn commit_to_batch(&mut self, batch: &mut DBTransaction) -> Result { + pub fn commit_to_batch(&mut self, batch: &mut DBTransaction) -> io::Result { let mut ret = 0u32; let mut deletes = 0usize; for i in self.overlay.drain() { @@ -106,14 +109,14 @@ impl OverlayDB { Some(x) => { let total_rc: i32 = x.count as i32 + rc; if total_rc < 0 { - return Err(From::from(BaseDataError::NegativelyReferencedHash(key))); + return Err(error_negatively_reference_hash(&key)); } let payload = Payload::new(total_rc as u32, x.value); deletes += if self.put_payload_in_batch(batch, &key, &payload) {1} else {0}; } None => { if rc < 0 { - return Err(From::from(BaseDataError::NegativelyReferencedHash(key))); + return Err(error_negatively_reference_hash(&key)); } let payload = Payload::new(rc as u32, value); self.put_payload_in_batch(batch, &key, &payload); @@ -152,7 +155,7 @@ impl OverlayDB { } } -impl HashDB for OverlayDB { +impl HashDB for OverlayDB { fn keys(&self) -> HashMap { let mut ret: HashMap = self.backing.iter(self.column) .map(|(key, _)| { diff --git a/util/journaldb/src/overlayrecentdb.rs b/util/journaldb/src/overlayrecentdb.rs index c7153b889d4..b63168e547c 100644 --- a/util/journaldb/src/overlayrecentdb.rs +++ b/util/journaldb/src/overlayrecentdb.rs @@ -18,19 +18,20 @@ use std::collections::HashMap; use std::collections::hash_map::Entry; +use std::io; use std::sync::Arc; -use parking_lot::RwLock; -use heapsize::HeapSizeOf; -use rlp::{Rlp, RlpStream, encode, decode, DecoderError, Decodable, Encodable}; + +use bytes::Bytes; +use ethereum_types::H256; use hashdb::*; -use memorydb::*; -use super::{DB_PREFIX_LEN, LATEST_ERA_KEY}; +use heapsize::HeapSizeOf; +use keccak_hasher::KeccakHasher; use kvdb::{KeyValueDB, DBTransaction}; -use super::JournalDB; -use ethereum_types::H256; +use memorydb::*; +use parking_lot::RwLock; use plain_hasher::H256FastMap; -use error::{BaseDataError, UtilError}; -use bytes::Bytes; +use rlp::{Rlp, RlpStream, encode, decode, DecoderError, Decodable, Encodable}; +use super::{DB_PREFIX_LEN, LATEST_ERA_KEY, JournalDB, error_negatively_reference_hash}; use util::DatabaseKey; /// Implementation of the `JournalDB` trait for a disk-backed database with a memory overlay @@ -65,7 +66,7 @@ use util::DatabaseKey; /// 7. Delete ancient record from memory and disk. pub struct OverlayRecentDB { - transaction_overlay: MemoryDB, + transaction_overlay: MemoryDB, backing: Arc, journal_overlay: Arc>, column: Option, @@ -119,7 +120,7 @@ impl<'a> Encodable for DatabaseValueRef<'a> { #[derive(PartialEq)] struct JournalOverlay { - backing_overlay: MemoryDB, // Nodes added in the history period + backing_overlay: MemoryDB, // Nodes added in the history period pending_overlay: H256FastMap, // Nodes being transfered from backing_overlay to backing db journal: HashMap>, latest_era: Option, @@ -282,7 +283,7 @@ impl JournalDB for OverlayRecentDB { .or_else(|| self.backing.get_by_prefix(self.column, &key[0..DB_PREFIX_LEN]).map(|b| b.into_vec())) } - fn journal_under(&mut self, batch: &mut DBTransaction, now: u64, id: &H256) -> Result { + fn journal_under(&mut self, batch: &mut DBTransaction, now: u64, id: &H256) -> io::Result { trace!(target: "journaldb", "entry: #{} ({})", now, id); let mut journal_overlay = self.journal_overlay.write(); @@ -338,7 +339,7 @@ impl JournalDB for OverlayRecentDB { Ok(ops as u32) } - fn mark_canonical(&mut self, batch: &mut DBTransaction, end_era: u64, canon_id: &H256) -> Result { + fn mark_canonical(&mut self, batch: &mut DBTransaction, end_era: u64, canon_id: &H256) -> io::Result { trace!(target: "journaldb", "canonical: #{} ({})", end_era, canon_id); let mut journal_overlay = self.journal_overlay.write(); @@ -410,7 +411,7 @@ impl JournalDB for OverlayRecentDB { self.journal_overlay.write().pending_overlay.clear(); } - fn inject(&mut self, batch: &mut DBTransaction) -> Result { + fn inject(&mut self, batch: &mut DBTransaction) -> io::Result { let mut ops = 0; for (key, (value, rc)) in self.transaction_overlay.drain() { if rc != 0 { ops += 1 } @@ -422,7 +423,7 @@ impl JournalDB for OverlayRecentDB { } -1 => { if cfg!(debug_assertions) && self.backing.get(self.column, &key)?.is_none() { - return Err(BaseDataError::NegativelyReferencedHash(key).into()); + return Err(error_negatively_reference_hash(&key)); } batch.delete(self.column, &key) } @@ -433,12 +434,12 @@ impl JournalDB for OverlayRecentDB { Ok(ops) } - fn consolidate(&mut self, with: MemoryDB) { + fn consolidate(&mut self, with: MemoryDB) { self.transaction_overlay.consolidate(with); } } -impl HashDB for OverlayRecentDB { +impl HashDB for OverlayRecentDB { fn keys(&self) -> HashMap { let mut ret: HashMap = self.backing.iter(self.column) .map(|(key, _)| (H256::from_slice(&*key), 1)) diff --git a/util/journaldb/src/refcounteddb.rs b/util/journaldb/src/refcounteddb.rs index cc81bbfba4d..7cbe9022d81 100644 --- a/util/journaldb/src/refcounteddb.rs +++ b/util/journaldb/src/refcounteddb.rs @@ -17,18 +17,20 @@ //! Disk-backed, ref-counted `JournalDB` implementation. use std::collections::HashMap; +use std::io; use std::sync::Arc; -use heapsize::HeapSizeOf; -use rlp::{encode, decode}; + +use bytes::Bytes; +use ethereum_types::H256; use hashdb::*; -use overlaydb::OverlayDB; +use heapsize::HeapSizeOf; +use keccak_hasher::KeccakHasher; +use kvdb::{KeyValueDB, DBTransaction}; use memorydb::MemoryDB; +use overlaydb::OverlayDB; +use rlp::{encode, decode}; use super::{DB_PREFIX_LEN, LATEST_ERA_KEY}; use super::traits::JournalDB; -use kvdb::{KeyValueDB, DBTransaction}; -use ethereum_types::H256; -use error::UtilError; -use bytes::Bytes; use util::{DatabaseKey, DatabaseValueView, DatabaseValueRef}; /// Implementation of the `HashDB` trait for a disk-backed database with a memory overlay @@ -78,7 +80,7 @@ impl RefCountedDB { } } -impl HashDB for RefCountedDB { +impl HashDB for RefCountedDB { fn keys(&self) -> HashMap { self.forward.keys() } fn get(&self, key: &H256) -> Option { self.forward.get(key) } fn contains(&self, key: &H256) -> bool { self.forward.contains(key) } @@ -117,7 +119,7 @@ impl JournalDB for RefCountedDB { self.backing.get_by_prefix(self.column, &id[0..DB_PREFIX_LEN]).map(|b| b.into_vec()) } - fn journal_under(&mut self, batch: &mut DBTransaction, now: u64, id: &H256) -> Result { + fn journal_under(&mut self, batch: &mut DBTransaction, now: u64, id: &H256) -> io::Result { // record new commit's details. let mut db_key = DatabaseKey { era: now, @@ -157,7 +159,7 @@ impl JournalDB for RefCountedDB { Ok(ops as u32) } - fn mark_canonical(&mut self, batch: &mut DBTransaction, end_era: u64, canon_id: &H256) -> Result { + fn mark_canonical(&mut self, batch: &mut DBTransaction, end_era: u64, canon_id: &H256) -> io::Result { // apply old commits' details let mut db_key = DatabaseKey { era: end_era, @@ -189,7 +191,7 @@ impl JournalDB for RefCountedDB { Ok(r) } - fn inject(&mut self, batch: &mut DBTransaction) -> Result { + fn inject(&mut self, batch: &mut DBTransaction) -> io::Result { self.inserts.clear(); for remove in self.removes.drain(..) { self.forward.remove(&remove); @@ -197,7 +199,7 @@ impl JournalDB for RefCountedDB { self.forward.commit_to_batch(batch) } - fn consolidate(&mut self, mut with: MemoryDB) { + fn consolidate(&mut self, mut with: MemoryDB) { for (key, (value, rc)) in with.drain() { for _ in 0..rc { self.emplace(key, value.clone()); diff --git a/util/journaldb/src/traits.rs b/util/journaldb/src/traits.rs index e37ac8aabf5..075a546005b 100644 --- a/util/journaldb/src/traits.rs +++ b/util/journaldb/src/traits.rs @@ -16,16 +16,18 @@ //! Disk-backed `HashDB` implementation. +use std::io; use std::sync::Arc; + +use bytes::Bytes; +use ethereum_types::H256; use hashdb::*; +use keccak_hasher::KeccakHasher; use kvdb::{self, DBTransaction}; -use ethereum_types::H256; -use error::UtilError; -use bytes::Bytes; /// A `HashDB` which can manage a short-term journal potentially containing many forks of mutually /// exclusive actions. -pub trait JournalDB: HashDB { +pub trait JournalDB: HashDB { /// Return a copy of ourself, in a box. fn boxed_clone(&self) -> Box; @@ -48,10 +50,10 @@ pub trait JournalDB: HashDB { /// Journal recent database operations as being associated with a given era and id. // TODO: give the overlay to this function so journaldbs don't manage the overlays themeselves. - fn journal_under(&mut self, batch: &mut DBTransaction, now: u64, id: &H256) -> Result; + fn journal_under(&mut self, batch: &mut DBTransaction, now: u64, id: &H256) -> io::Result; /// Mark a given block as canonical, indicating that competing blocks' states may be pruned out. - fn mark_canonical(&mut self, batch: &mut DBTransaction, era: u64, id: &H256) -> Result; + fn mark_canonical(&mut self, batch: &mut DBTransaction, era: u64, id: &H256) -> io::Result; /// Commit all queued insert and delete operations without affecting any journalling -- this requires that all insertions /// and deletions are indeed canonical and will likely lead to an invalid database if that assumption is violated. @@ -60,7 +62,7 @@ pub trait JournalDB: HashDB { /// by any previous `commit` operations. Essentially, this means that `inject` can be used /// either to restore a state to a fresh database, or to insert data which may only be journalled /// from this point onwards. - fn inject(&mut self, batch: &mut DBTransaction) -> Result; + fn inject(&mut self, batch: &mut DBTransaction) -> io::Result; /// State data query fn state(&self, _id: &H256) -> Option; @@ -76,11 +78,11 @@ pub trait JournalDB: HashDB { fn flush(&self) {} /// Consolidate all the insertions and deletions in the given memory overlay. - fn consolidate(&mut self, overlay: ::memorydb::MemoryDB); + fn consolidate(&mut self, overlay: ::memorydb::MemoryDB); /// Commit all changes in a single batch #[cfg(test)] - fn commit_batch(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { + fn commit_batch(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> io::Result { let mut batch = self.backing().transaction(); let mut ops = self.journal_under(&mut batch, now, id)?; @@ -95,7 +97,7 @@ pub trait JournalDB: HashDB { /// Inject all changes in a single batch. #[cfg(test)] - fn inject_batch(&mut self) -> Result { + fn inject_batch(&mut self) -> io::Result { let mut batch = self.backing().transaction(); let res = self.inject(&mut batch)?; self.backing().write(batch).map(|_| res).map_err(Into::into) diff --git a/util/keccak-hasher/Cargo.toml b/util/keccak-hasher/Cargo.toml new file mode 100644 index 00000000000..e7c8e950ec9 --- /dev/null +++ b/util/keccak-hasher/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "keccak-hasher" +version = "0.1.0" +authors = ["Parity Technologies "] +description = "Keccak-256 implementation of the Hasher trait" +license = "GPL-3.0" + +[dependencies] +ethereum-types = "0.3" +tiny-keccak = "1.4.2" +hashdb = { path = "../hashdb" } +plain_hasher = { path = "../plain_hasher" } \ No newline at end of file diff --git a/util/keccak-hasher/src/lib.rs b/util/keccak-hasher/src/lib.rs new file mode 100644 index 00000000000..bb2b5b45ffe --- /dev/null +++ b/util/keccak-hasher/src/lib.rs @@ -0,0 +1,39 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Hasher implementation for the Keccak-256 hash +extern crate hashdb; +extern crate ethereum_types; +extern crate tiny_keccak; +extern crate plain_hasher; + +use hashdb::Hasher; +use ethereum_types::H256; +use tiny_keccak::Keccak; +use plain_hasher::PlainHasher; +/// Concrete `Hasher` impl for the Keccak-256 hash +#[derive(Default, Debug, Clone, PartialEq)] +pub struct KeccakHasher; +impl Hasher for KeccakHasher { + type Out = H256; + type StdHasher = PlainHasher; + const LENGTH: usize = 32; + fn hash(x: &[u8]) -> Self::Out { + let mut out = [0;32]; + Keccak::keccak256(x, &mut out); + out.into() + } +} diff --git a/util/kvdb-memorydb/Cargo.toml b/util/kvdb-memorydb/Cargo.toml index 4dbad628c42..a70b1e3da6f 100644 --- a/util/kvdb-memorydb/Cargo.toml +++ b/util/kvdb-memorydb/Cargo.toml @@ -4,5 +4,5 @@ version = "0.1.0" authors = ["Parity Technologies "] [dependencies] -parking_lot = "0.5" +parking_lot = "0.6" kvdb = { path = "../kvdb" } diff --git a/util/kvdb-rocksdb/Cargo.toml b/util/kvdb-rocksdb/Cargo.toml index d49d8385d22..c580502f53e 100644 --- a/util/kvdb-rocksdb/Cargo.toml +++ b/util/kvdb-rocksdb/Cargo.toml @@ -11,7 +11,7 @@ interleaved-ordered = "0.1.0" kvdb = { path = "../kvdb" } log = "0.3" num_cpus = "1.0" -parking_lot = "0.5" +parking_lot = "0.6" regex = "0.2" rocksdb = { git = "https://github.com/paritytech/rust-rocksdb" } diff --git a/util/memorydb/Cargo.toml b/util/memorydb/Cargo.toml index 41c41bb628e..57d7439cfeb 100644 --- a/util/memorydb/Cargo.toml +++ b/util/memorydb/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "memorydb" -version = "0.1.1" +version = "0.2.0" authors = ["Parity Technologies "] description = "in-memory implementation of hashdb" license = "GPL-3.0" @@ -8,8 +8,12 @@ license = "GPL-3.0" [dependencies] elastic-array = "0.10" heapsize = "0.4" -ethereum-types = "0.3" -keccak-hash = { version = "0.1.0", path = "../hash" } -hashdb = { version = "0.1.1", path = "../hashdb" } +hashdb = { version = "0.2.0", path = "../hashdb" } plain_hasher = { path = "../plain_hasher" } rlp = { version = "0.2.1", path = "../rlp" } + +[dev-dependencies] +tiny-keccak = "1.4.2" +ethereum-types = "0.3" +keccak-hasher = { path = "../keccak-hasher" } +keccak-hash = { path = "../hash" } \ No newline at end of file diff --git a/util/memorydb/benches/memdb.rs b/util/memorydb/benches/memdb.rs new file mode 100644 index 00000000000..cfc676ccd50 --- /dev/null +++ b/util/memorydb/benches/memdb.rs @@ -0,0 +1,79 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +#![feature(test)] + +extern crate hashdb; +extern crate memorydb; +extern crate keccak_hasher; +extern crate keccak_hash; +extern crate rlp; +extern crate test; + +use memorydb::MemoryDB; +use keccak_hasher::KeccakHasher; +use hashdb::{HashDB, Hasher}; +use keccak_hash::KECCAK_NULL_RLP; +use rlp::NULL_RLP; +use test::{Bencher, black_box}; + + +#[bench] +fn instantiation(b: &mut Bencher) { + b.iter(|| { + MemoryDB::::new(); + }) +} + +#[bench] +fn compare_to_null_embedded_in_struct(b: &mut Bencher) { + struct X {a_hash: ::Out}; + let x = X {a_hash: KeccakHasher::hash(&NULL_RLP)}; + let key = KeccakHasher::hash(b"abc"); + + b.iter(|| { + black_box(key == x.a_hash); + }) +} + +#[bench] +fn compare_to_null_in_const(b: &mut Bencher) { + let key = KeccakHasher::hash(b"abc"); + + b.iter(|| { + black_box(key == KECCAK_NULL_RLP); + }) +} + +#[bench] +fn contains_with_non_null_key(b: &mut Bencher) { + let mut m = MemoryDB::::new(); + let key = KeccakHasher::hash(b"abc"); + m.insert(b"abcefghijklmnopqrstuvxyz"); + b.iter(|| { + m.contains(&key); + }) +} + +#[bench] +fn contains_with_null_key(b: &mut Bencher) { + let mut m = MemoryDB::::new(); + let null_key = KeccakHasher::hash(&NULL_RLP); + m.insert(b"abcefghijklmnopqrstuvxyz"); + b.iter(|| { + m.contains(&null_key); + }) +} \ No newline at end of file diff --git a/util/memorydb/src/lib.rs b/util/memorydb/src/lib.rs index e297d1e6d1a..538738995c1 100644 --- a/util/memorydb/src/lib.rs +++ b/util/memorydb/src/lib.rs @@ -15,23 +15,25 @@ // along with Parity. If not, see . //! Reference-counted memory-based `HashDB` implementation. -extern crate heapsize; -extern crate ethereum_types; +extern crate elastic_array; extern crate hashdb; -extern crate keccak_hash as keccak; -extern crate plain_hasher; +extern crate heapsize; extern crate rlp; -extern crate elastic_array; +#[cfg(test)] extern crate keccak_hasher; +#[cfg(test)] extern crate tiny_keccak; +#[cfg(test)] extern crate ethereum_types; -use std::mem; -use std::collections::HashMap; -use std::collections::hash_map::Entry; +use hashdb::{HashDB, Hasher as KeyHasher, DBValue, AsHashDB}; use heapsize::HeapSizeOf; -use ethereum_types::H256; -use hashdb::{HashDB, DBValue}; -use keccak::{KECCAK_NULL_RLP, keccak}; -use plain_hasher::H256FastMap; use rlp::NULL_RLP; +use std::collections::hash_map::Entry; +use std::collections::HashMap; +use std::hash; +use std::mem; + +// Backing `HashMap` parametrized with a `Hasher` for the keys `Hasher::Out` and the `Hasher::StdHasher` as hash map builder. +type FastMap = HashMap<::Out, T, hash::BuildHasherDefault<::StdHasher>>; + /// Reference-counted memory-based `HashDB` implementation. /// /// Use `new()` to create a new database. Insert items with `insert()`, remove items @@ -42,11 +44,14 @@ use rlp::NULL_RLP; /// # Example /// ```rust /// extern crate hashdb; +/// extern crate keccak_hasher; /// extern crate memorydb; +/// /// use hashdb::*; +/// use keccak_hasher::KeccakHasher; /// use memorydb::*; /// fn main() { -/// let mut m = MemoryDB::new(); +/// let mut m = MemoryDB::::new(); /// let d = "Hello world!".as_bytes(); /// /// let k = m.insert(d); @@ -77,15 +82,17 @@ use rlp::NULL_RLP; /// } /// ``` #[derive(Default, Clone, PartialEq)] -pub struct MemoryDB { - data: H256FastMap<(DBValue, i32)>, +pub struct MemoryDB { + data: FastMap, + hashed_null_node: H::Out, } -impl MemoryDB { +impl MemoryDB { /// Create a new instance of the memory DB. - pub fn new() -> MemoryDB { + pub fn new() -> MemoryDB { MemoryDB { - data: H256FastMap::default(), + data: FastMap::::default(), + hashed_null_node: H::hash(&NULL_RLP) } } @@ -94,11 +101,15 @@ impl MemoryDB { /// # Examples /// ```rust /// extern crate hashdb; + /// extern crate keccak_hasher; /// extern crate memorydb; + /// /// use hashdb::*; + /// use keccak_hasher::KeccakHasher; /// use memorydb::*; + /// /// fn main() { - /// let mut m = MemoryDB::new(); + /// let mut m = MemoryDB::::new(); /// let hello_bytes = "Hello world!".as_bytes(); /// let hash = m.insert(hello_bytes); /// assert!(m.contains(&hash)); @@ -116,8 +127,8 @@ impl MemoryDB { } /// Return the internal map of hashes to data, clearing the current state. - pub fn drain(&mut self) -> H256FastMap<(DBValue, i32)> { - mem::replace(&mut self.data, H256FastMap::default()) + pub fn drain(&mut self) -> FastMap { + mem::replace(&mut self.data, FastMap::::default()) } /// Grab the raw information associated with a key. Returns None if the key @@ -125,8 +136,8 @@ impl MemoryDB { /// /// Even when Some is returned, the data is only guaranteed to be useful /// when the refs > 0. - pub fn raw(&self, key: &H256) -> Option<(DBValue, i32)> { - if key == &KECCAK_NULL_RLP { + pub fn raw(&self, key: &::Out) -> Option<(DBValue, i32)> { + if key == &self.hashed_null_node { return Some((DBValue::from_slice(&NULL_RLP), 1)); } self.data.get(key).cloned() @@ -139,8 +150,8 @@ impl MemoryDB { /// Remove an element and delete it from storage if reference count reaches zero. /// If the value was purged, return the old value. - pub fn remove_and_purge(&mut self, key: &H256) -> Option { - if key == &KECCAK_NULL_RLP { + pub fn remove_and_purge(&mut self, key: &::Out) -> Option { + if key == &self.hashed_null_node { return None; } match self.data.entry(key.clone()) { @@ -177,19 +188,9 @@ impl MemoryDB { } } -impl HashDB for MemoryDB { - fn get(&self, key: &H256) -> Option { - if key == &KECCAK_NULL_RLP { - return Some(DBValue::from_slice(&NULL_RLP)); - } +impl HashDB for MemoryDB { - match self.data.get(key) { - Some(&(ref d, rc)) if rc > 0 => Some(d.clone()), - _ => None - } - } - - fn keys(&self) -> HashMap { + fn keys(&self) -> HashMap { self.data.iter() .filter_map(|(k, v)| if v.1 != 0 { Some((*k, v.1)) @@ -199,8 +200,19 @@ impl HashDB for MemoryDB { .collect() } - fn contains(&self, key: &H256) -> bool { - if key == &KECCAK_NULL_RLP { + fn get(&self, key: &H::Out) -> Option { + if key == &self.hashed_null_node { + return Some(DBValue::from_slice(&NULL_RLP)); + } + + match self.data.get(key) { + Some(&(ref d, rc)) if rc > 0 => Some(d.clone()), + _ => None + } + } + + fn contains(&self, key: &H::Out) -> bool { + if key == &self.hashed_null_node { return true; } @@ -210,15 +222,15 @@ impl HashDB for MemoryDB { } } - fn insert(&mut self, value: &[u8]) -> H256 { + fn insert(&mut self, value: &[u8]) -> H::Out { if value == &NULL_RLP { - return KECCAK_NULL_RLP.clone(); + return self.hashed_null_node.clone(); } - let key = keccak(value); + let key = H::hash(value); match self.data.entry(key) { Entry::Occupied(mut entry) => { let &mut (ref mut old_value, ref mut rc) = entry.get_mut(); - if *rc >= -0x80000000i32 && *rc <= 0 { + if *rc <= 0 { *old_value = DBValue::from_slice(value); } *rc += 1; @@ -230,7 +242,7 @@ impl HashDB for MemoryDB { key } - fn emplace(&mut self, key: H256, value: DBValue) { + fn emplace(&mut self, key:H::Out, value: DBValue) { if &*value == &NULL_RLP { return; } @@ -238,7 +250,7 @@ impl HashDB for MemoryDB { match self.data.entry(key) { Entry::Occupied(mut entry) => { let &mut (ref mut old_value, ref mut rc) = entry.get_mut(); - if *rc >= -0x80000000i32 && *rc <= 0 { + if *rc <= 0 { *old_value = value; } *rc += 1; @@ -249,8 +261,8 @@ impl HashDB for MemoryDB { } } - fn remove(&mut self, key: &H256) { - if key == &KECCAK_NULL_RLP { + fn remove(&mut self, key: &H::Out) { + if key == &self.hashed_null_node { return; } @@ -266,17 +278,26 @@ impl HashDB for MemoryDB { } } +impl AsHashDB for MemoryDB { + fn as_hashdb(&self) -> &HashDB { self } + fn as_hashdb_mut(&mut self) -> &mut HashDB { self } +} + #[cfg(test)] mod tests { - use keccak::keccak; use super::*; + use tiny_keccak::Keccak; + use ethereum_types::H256; + use keccak_hasher::KeccakHasher; #[test] fn memorydb_remove_and_purge() { let hello_bytes = b"Hello world!"; - let hello_key = keccak(hello_bytes); + let mut hello_key = [0;32]; + Keccak::keccak256(hello_bytes, &mut hello_key); + let hello_key = H256(hello_key); - let mut m = MemoryDB::new(); + let mut m = MemoryDB::::new(); m.remove(&hello_key); assert_eq!(m.raw(&hello_key).unwrap().1, -1); m.purge(); @@ -286,7 +307,7 @@ mod tests { m.purge(); assert_eq!(m.raw(&hello_key), None); - let mut m = MemoryDB::new(); + let mut m = MemoryDB::::new(); assert!(m.remove_and_purge(&hello_key).is_none()); assert_eq!(m.raw(&hello_key).unwrap().1, -1); m.insert(hello_bytes); @@ -299,8 +320,8 @@ mod tests { #[test] fn consolidate() { - let mut main = MemoryDB::new(); - let mut other = MemoryDB::new(); + let mut main = MemoryDB::::new(); + let mut other = MemoryDB::::new(); let remove_key = other.insert(b"doggo"); main.remove(&remove_key); diff --git a/util/network-devp2p/Cargo.toml b/util/network-devp2p/Cargo.toml index 4b094da95b6..3e483c1d89d 100644 --- a/util/network-devp2p/Cargo.toml +++ b/util/network-devp2p/Cargo.toml @@ -16,7 +16,7 @@ rust-crypto = "0.2.34" slab = "0.2" igd = "0.7" libc = "0.2.7" -parking_lot = "0.5" +parking_lot = "0.6" ansi_term = "0.10" rustc-hex = "1.0" ethcore-io = { path = "../io", features = ["mio"] } diff --git a/util/path/Cargo.toml b/util/path/Cargo.toml index 7df3917b140..6d01d6488f3 100644 --- a/util/path/Cargo.toml +++ b/util/path/Cargo.toml @@ -1,6 +1,8 @@ [package] name = "path" -version = "0.1.0" -authors = ["debris "] +version = "0.1.1" +authors = ["Parity Technologies "] +license = "GPL3" [dependencies] +dirs = "1.0.2" diff --git a/util/path/src/lib.rs b/util/path/src/lib.rs index 38608db6604..3169274ad83 100644 --- a/util/path/src/lib.rs +++ b/util/path/src/lib.rs @@ -15,6 +15,8 @@ // along with Parity. If not, see . //! Path utilities +extern crate dirs; + use std::path::Path; use std::path::PathBuf; @@ -22,7 +24,7 @@ use std::path::PathBuf; /// Get the config path for application `name`. /// `name` should be capitalized, e.g. `"Ethereum"`, `"Parity"`. pub fn config_path(name: &str) -> PathBuf { - let mut home = ::std::env::home_dir().expect("Failed to get home dir"); + let mut home = dirs::home_dir().expect("Failed to get home dir"); home.push("Library"); home.push(name); home @@ -32,7 +34,7 @@ pub fn config_path(name: &str) -> PathBuf { /// Get the config path for application `name`. /// `name` should be capitalized, e.g. `"Ethereum"`, `"Parity"`. pub fn config_path(name: &str) -> PathBuf { - let mut home = ::std::env::home_dir().expect("Failed to get home dir"); + let mut home = dirs::home_dir().expect("Failed to get home dir"); home.push("AppData"); home.push("Roaming"); home.push(name); @@ -43,7 +45,7 @@ pub fn config_path(name: &str) -> PathBuf { /// Get the config path for application `name`. /// `name` should be capitalized, e.g. `"Ethereum"`, `"Parity"`. pub fn config_path(name: &str) -> PathBuf { - let mut home = ::std::env::home_dir().expect("Failed to get home dir"); + let mut home = dirs::home_dir().expect("Failed to get home dir"); home.push(format!(".{}", name.to_lowercase())); home } diff --git a/util/patricia-trie-ethereum/Cargo.toml b/util/patricia-trie-ethereum/Cargo.toml new file mode 100644 index 00000000000..239c7c99f03 --- /dev/null +++ b/util/patricia-trie-ethereum/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "patricia-trie-ethereum" +version = "0.1.0" +authors = ["Parity Technologies "] +description = "Merkle-Patricia Trie (Ethereum Style)" +license = "GPL-3.0" + +[dependencies] +patricia-trie = { path = "../patricia_trie" } +keccak-hasher = { path = "../keccak-hasher" } +hashdb = { path = "../hashdb" } +rlp = { path = "../rlp" } +ethcore-bytes = { path = "../bytes" } +ethereum-types = "0.3" +elastic-array = "0.10" \ No newline at end of file diff --git a/util/patricia-trie-ethereum/src/lib.rs b/util/patricia-trie-ethereum/src/lib.rs new file mode 100644 index 00000000000..a252152c776 --- /dev/null +++ b/util/patricia-trie-ethereum/src/lib.rs @@ -0,0 +1,62 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Façade crate for `patricia_trie` for Ethereum specific impls + +pub extern crate patricia_trie as trie; // `pub` because we need to import this crate for the tests in `patricia_trie` and there were issues: https://gist.github.com/dvdplm/869251ee557a1b4bd53adc7c971979aa +extern crate elastic_array; +extern crate ethcore_bytes; +extern crate ethereum_types; +extern crate hashdb; +extern crate keccak_hasher; +extern crate rlp; + +mod rlp_node_codec; + +pub use rlp_node_codec::RlpNodeCodec; + +use ethereum_types::H256; +use keccak_hasher::KeccakHasher; +use rlp::DecoderError; + +/// Convenience type alias to instantiate a Keccak-flavoured `RlpNodeCodec` +pub type RlpCodec = RlpNodeCodec; + +/// Convenience type alias to instantiate a Keccak/Rlp-flavoured `TrieDB` +pub type TrieDB<'db> = trie::TrieDB<'db, KeccakHasher, RlpCodec>; + +/// Convenience type alias to instantiate a Keccak/Rlp-flavoured `SecTrieDB` +pub type SecTrieDB<'db> = trie::SecTrieDB<'db, KeccakHasher, RlpCodec>; + +/// Convenience type alias to instantiate a Keccak/Rlp-flavoured `FatDB` +pub type FatDB<'db> = trie::FatDB<'db, KeccakHasher, RlpCodec>; + +/// Convenience type alias to instantiate a Keccak/Rlp-flavoured `TrieDBMut` +pub type TrieDBMut<'db> = trie::TrieDBMut<'db, KeccakHasher, RlpCodec>; + +/// Convenience type alias to instantiate a Keccak/Rlp-flavoured `SecTrieDBMut` +pub type SecTrieDBMut<'db> = trie::SecTrieDBMut<'db, KeccakHasher, RlpCodec>; + +/// Convenience type alias to instantiate a Keccak/Rlp-flavoured `FatDBMut` +pub type FatDBMut<'db> = trie::FatDBMut<'db, KeccakHasher, RlpCodec>; + +/// Convenience type alias to instantiate a Keccak/Rlp-flavoured `TrieFactory` +pub type TrieFactory = trie::TrieFactory; + +/// Convenience type alias for Keccak/Rlp flavoured trie errors +pub type TrieError = trie::TrieError; +/// Convenience type alias for Keccak/Rlp flavoured trie results +pub type Result = trie::Result; diff --git a/util/patricia-trie-ethereum/src/rlp_node_codec.rs b/util/patricia-trie-ethereum/src/rlp_node_codec.rs new file mode 100644 index 00000000000..414a129efe8 --- /dev/null +++ b/util/patricia-trie-ethereum/src/rlp_node_codec.rs @@ -0,0 +1,124 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! `NodeCodec` implementation for Rlp + +use elastic_array::{ElasticArray1024, ElasticArray128}; +use ethereum_types::H256; +use hashdb::Hasher; +use keccak_hasher::KeccakHasher; +use rlp::{DecoderError, RlpStream, Rlp, Prototype}; +use std::marker::PhantomData; +use trie::{NibbleSlice, NodeCodec, node::Node, ChildReference}; + +/// Concrete implementation of a `NodeCodec` with Rlp encoding, generic over the `Hasher` +#[derive(Default, Clone)] +pub struct RlpNodeCodec {mark: PhantomData} + +// NOTE: what we'd really like here is: +// `impl NodeCodec for RlpNodeCodec where H::Out: Decodable` +// but due to the current limitations of Rust const evaluation we can't +// do `const HASHED_NULL_NODE: H::Out = H::Out( … … )`. Perhaps one day soon? +impl NodeCodec for RlpNodeCodec { + type Error = DecoderError; + const HASHED_NULL_NODE : H256 = H256( [0x56, 0xe8, 0x1f, 0x17, 0x1b, 0xcc, 0x55, 0xa6, 0xff, 0x83, 0x45, 0xe6, 0x92, 0xc0, 0xf8, 0x6e, 0x5b, 0x48, 0xe0, 0x1b, 0x99, 0x6c, 0xad, 0xc0, 0x01, 0x62, 0x2f, 0xb5, 0xe3, 0x63, 0xb4, 0x21] ); + fn decode(data: &[u8]) -> ::std::result::Result { + let r = Rlp::new(data); + match r.prototype()? { + // either leaf or extension - decode first item with NibbleSlice::??? + // and use is_leaf return to figure out which. + // if leaf, second item is a value (is_data()) + // if extension, second item is a node (either SHA3 to be looked up and + // fed back into this function or inline RLP which can be fed back into this function). + Prototype::List(2) => match NibbleSlice::from_encoded(r.at(0)?.data()?) { + (slice, true) => Ok(Node::Leaf(slice, r.at(1)?.data()?)), + (slice, false) => Ok(Node::Extension(slice, r.at(1)?.as_raw())), + }, + // branch - first 16 are nodes, 17th is a value (or empty). + Prototype::List(17) => { + let mut nodes = [&[] as &[u8]; 16]; + for i in 0..16 { + nodes[i] = r.at(i)?.as_raw(); + } + Ok(Node::Branch(nodes, if r.at(16)?.is_empty() { None } else { Some(r.at(16)?.data()?) })) + }, + // an empty branch index. + Prototype::Data(0) => Ok(Node::Empty), + // something went wrong. + _ => Err(DecoderError::Custom("Rlp is not valid.")) + } + } + fn try_decode_hash(data: &[u8]) -> Option<::Out> { + let r = Rlp::new(data); + if r.is_data() && r.size() == KeccakHasher::LENGTH { + Some(r.as_val().expect("Hash is the correct size; qed")) + } else { + None + } + } + fn is_empty_node(data: &[u8]) -> bool { + Rlp::new(data).is_empty() + } + fn empty_node() -> ElasticArray1024 { + let mut stream = RlpStream::new(); + stream.append_empty_data(); + stream.drain() + } + + fn leaf_node(partial: &[u8], value: &[u8]) -> ElasticArray1024 { + let mut stream = RlpStream::new_list(2); + stream.append(&partial); + stream.append(&value); + stream.drain() + } + + fn ext_node(partial: &[u8], child_ref: ChildReference<::Out>) -> ElasticArray1024 { + let mut stream = RlpStream::new_list(2); + stream.append(&partial); + match child_ref { + ChildReference::Hash(h) => stream.append(&h), + ChildReference::Inline(inline_data, len) => { + let bytes = &AsRef::<[u8]>::as_ref(&inline_data)[..len]; + stream.append_raw(bytes, 1) + }, + }; + stream.drain() + } + + fn branch_node(children: I, value: Option>) -> ElasticArray1024 + where I: IntoIterator::Out>>> + { + let mut stream = RlpStream::new_list(17); + for child_ref in children { + match child_ref { + Some(c) => match c { + ChildReference::Hash(h) => stream.append(&h), + ChildReference::Inline(inline_data, len) => { + let bytes = &AsRef::<[u8]>::as_ref(&inline_data)[..len]; + stream.append_raw(bytes, 1) + }, + }, + None => stream.append_empty_data() + }; + } + if let Some(value) = value { + stream.append(&&*value); + } else { + stream.append_empty_data(); + } + stream.drain() + } +} diff --git a/util/patricia_trie/Cargo.toml b/util/patricia_trie/Cargo.toml index 48b06b21463..ebd66504546 100644 --- a/util/patricia_trie/Cargo.toml +++ b/util/patricia_trie/Cargo.toml @@ -1,22 +1,25 @@ [package] name = "patricia-trie" -version = "0.1.0" +version = "0.2.0" authors = ["Parity Technologies "] -description = "Merkle-Patricia Trie (Ethereum Style)" +description = "Merkle-Patricia Trie generic over key hasher and node encoding" license = "GPL-3.0" [dependencies] elastic-array = "0.10" +ethcore-bytes = { version = "0.1.0", path = "../bytes" } +hashdb = { version = "0.2", path = "../hashdb" } +heapsize = "0.4" log = "0.3" rand = "0.4" -ethcore-bytes = { version = "0.1.0", path = "../bytes" } + +[dev-dependencies] +env_logger = "0.5" ethereum-types = "0.3" keccak-hash = { version = "0.1.0", path = "../hash" } -hashdb = { version = "0.1.1", path = "../hashdb" } +keccak-hasher = { path = "../keccak-hasher" } +memorydb = { version = "0.2", path = "../memorydb" } +patricia-trie-ethereum = { path = "../patricia-trie-ethereum" } rlp = { version = "0.2.1", path = "../rlp" } -triehash = { version = "0.1.0", path = "../triehash" } -memorydb = { version = "0.1.0", path = "../memorydb" } -ethcore-logger = { version = "1.9.0", path = "../../logger" } - -[dev-dependencies] trie-standardmap = { path = "../trie-standardmap" } +triehash = { version = "0.1.0", path = "../triehash" } diff --git a/util/patricia_trie/benches/trie.rs b/util/patricia_trie/benches/trie.rs index f26febdb595..114006ebe2e 100644 --- a/util/patricia_trie/benches/trie.rs +++ b/util/patricia_trie/benches/trie.rs @@ -21,16 +21,21 @@ extern crate ethcore_bytes; extern crate ethereum_types; extern crate memorydb; extern crate patricia_trie as trie; +extern crate patricia_trie_ethereum as ethtrie; +extern crate keccak_hasher; extern crate keccak_hash; extern crate trie_standardmap; +extern crate hashdb; use ethcore_bytes::Bytes; use ethereum_types::H256; use keccak_hash::keccak; use memorydb::MemoryDB; use test::{Bencher, black_box}; -use trie::{TrieDBMut, TrieDB, TrieMut, Trie}; +use trie::{TrieMut, Trie}; use trie_standardmap::{Alphabet, ValueMode, StandardMap}; +use keccak_hasher::KeccakHasher; +use ethtrie::{TrieDB, TrieDBMut}; fn random_word(alphabet: &[u8], min_count: usize, diff_count: usize, seed: &mut H256) -> Vec { assert!(min_count + diff_count <= 32); @@ -69,7 +74,7 @@ fn trie_insertions_32_mir_1k(b: &mut Bencher) { }; let d = st.make(); b.iter(&mut ||{ - let mut memdb = MemoryDB::new(); + let mut memdb = MemoryDB::::new(); let mut root = H256::new(); let mut t = TrieDBMut::new(&mut memdb, &mut root); for i in d.iter() { @@ -87,7 +92,7 @@ fn trie_iter(b: &mut Bencher) { count: 1000, }; let d = st.make(); - let mut memdb = MemoryDB::new(); + let mut memdb = MemoryDB::::new(); let mut root = H256::new(); { let mut t = TrieDBMut::new(&mut memdb, &mut root); @@ -116,7 +121,7 @@ fn trie_insertions_32_ran_1k(b: &mut Bencher) { let d = st.make(); let mut r = H256::new(); b.iter(&mut ||{ - let mut memdb = MemoryDB::new(); + let mut memdb = MemoryDB::::new(); let mut root = H256::new(); let mut t = TrieDBMut::new(&mut memdb, &mut root); for i in d.iter() { @@ -137,7 +142,7 @@ fn trie_insertions_six_high(b: &mut Bencher) { } b.iter(||{ - let mut memdb = MemoryDB::new(); + let mut memdb = MemoryDB::::new(); let mut root = H256::new(); let mut t = TrieDBMut::new(&mut memdb, &mut root); for i in d.iter() { @@ -157,7 +162,7 @@ fn trie_insertions_six_mid(b: &mut Bencher) { d.push((k, v)) } b.iter(||{ - let mut memdb = MemoryDB::new(); + let mut memdb = MemoryDB::::new(); let mut root = H256::new(); let mut t = TrieDBMut::new(&mut memdb, &mut root); for i in d.iter() { @@ -178,7 +183,7 @@ fn trie_insertions_random_mid(b: &mut Bencher) { } b.iter(||{ - let mut memdb = MemoryDB::new(); + let mut memdb = MemoryDB::::new(); let mut root = H256::new(); let mut t = TrieDBMut::new(&mut memdb, &mut root); for i in d.iter() { @@ -199,7 +204,7 @@ fn trie_insertions_six_low(b: &mut Bencher) { } b.iter(||{ - let mut memdb = MemoryDB::new(); + let mut memdb = MemoryDB::::new(); let mut root = H256::new(); let mut t = TrieDBMut::new(&mut memdb, &mut root); for i in d.iter() { diff --git a/util/patricia_trie/src/fatdb.rs b/util/patricia_trie/src/fatdb.rs index 90cdef90214..34a49a5d0f6 100644 --- a/util/patricia_trie/src/fatdb.rs +++ b/util/patricia_trie/src/fatdb.rs @@ -14,66 +14,77 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use ethereum_types::H256; -use keccak::keccak; -use hashdb::HashDB; -use super::{TrieDB, Trie, TrieDBIterator, TrieItem, TrieIterator, Query}; +use hashdb::{HashDB, Hasher}; +use super::{Result, TrieDB, Trie, TrieDBIterator, TrieItem, TrieIterator, Query}; +use node_codec::NodeCodec; /// A `Trie` implementation which hashes keys and uses a generic `HashDB` backing database. /// Additionaly it stores inserted hash-key mappings for later retrieval. /// /// Use it as a `Trie` or `TrieMut` trait object. -pub struct FatDB<'db> { - raw: TrieDB<'db>, +pub struct FatDB<'db, H, C> +where + H: Hasher + 'db, + C: NodeCodec +{ + raw: TrieDB<'db, H, C>, } -impl<'db> FatDB<'db> { +impl<'db, H, C> FatDB<'db, H, C> +where + H: Hasher, + C: NodeCodec +{ /// Create a new trie with the backing database `db` and empty `root` /// Initialise to the state entailed by the genesis block. /// This guarantees the trie is built correctly. - pub fn new(db: &'db HashDB, root: &'db H256) -> super::Result { - let fatdb = FatDB { - raw: TrieDB::new(db, root)? - }; - - Ok(fatdb) + pub fn new(db: &'db HashDB, root: &'db H::Out) -> Result { + Ok(FatDB { raw: TrieDB::new(db, root)? }) } /// Get the backing database. - pub fn db(&self) -> &HashDB { - self.raw.db() - } + pub fn db(&self) -> &HashDB { self.raw.db() } } -impl<'db> Trie for FatDB<'db> { - fn iter<'a>(&'a self) -> super::Result + 'a>> { - FatDBIterator::new(&self.raw).map(|iter| Box::new(iter) as Box<_>) - } - - fn root(&self) -> &H256 { - self.raw.root() - } +impl<'db, H, C> Trie for FatDB<'db, H, C> +where + H: Hasher, + C: NodeCodec +{ + fn root(&self) -> &H::Out { self.raw.root() } - fn contains(&self, key: &[u8]) -> super::Result { - self.raw.contains(&keccak(key)) + fn contains(&self, key: &[u8]) -> Result { + self.raw.contains(H::hash(key).as_ref()) } - fn get_with<'a, 'key, Q: Query>(&'a self, key: &'key [u8], query: Q) -> super::Result> + fn get_with<'a, 'key, Q: Query>(&'a self, key: &'key [u8], query: Q) -> Result, H::Out, C::Error> where 'a: 'key { - self.raw.get_with(&keccak(key), query) + self.raw.get_with(H::hash(key).as_ref(), query) + } + + fn iter<'a>(&'a self) -> Result> + 'a>, ::Out, C::Error> { + FatDBIterator::::new(&self.raw).map(|iter| Box::new(iter) as Box<_>) } } /// Itarator over inserted pairs of key values. -pub struct FatDBIterator<'db> { - trie_iterator: TrieDBIterator<'db>, - trie: &'db TrieDB<'db>, +pub struct FatDBIterator<'db, H, C> +where + H: Hasher + 'db, + C: NodeCodec + 'db +{ + trie_iterator: TrieDBIterator<'db, H, C>, + trie: &'db TrieDB<'db, H, C>, } -impl<'db> FatDBIterator<'db> { +impl<'db, H, C> FatDBIterator<'db, H, C> +where + H: Hasher, + C: NodeCodec +{ /// Creates new iterator. - pub fn new(trie: &'db TrieDB) -> super::Result { + pub fn new(trie: &'db TrieDB) -> Result { Ok(FatDBIterator { trie_iterator: TrieDBIterator::new(trie)?, trie: trie, @@ -81,40 +92,56 @@ impl<'db> FatDBIterator<'db> { } } -impl<'db> TrieIterator for FatDBIterator<'db> { - fn seek(&mut self, key: &[u8]) -> super::Result<()> { - self.trie_iterator.seek(&keccak(key)) +impl<'db, H, C> TrieIterator for FatDBIterator<'db, H, C> +where + H: Hasher, + C: NodeCodec +{ + fn seek(&mut self, key: &[u8]) -> Result<(), H::Out, C::Error> { + let hashed_key = H::hash(key); + self.trie_iterator.seek(hashed_key.as_ref()) } } -impl<'db> Iterator for FatDBIterator<'db> { - type Item = TrieItem<'db>; +impl<'db, H, C> Iterator for FatDBIterator<'db, H, C> +where + H: Hasher, + C: NodeCodec +{ + type Item = TrieItem<'db, H::Out, C::Error>; fn next(&mut self) -> Option { self.trie_iterator.next() - .map(|res| + .map(|res| { res.map(|(hash, value)| { - let aux_hash = keccak(hash); + let aux_hash = H::hash(&hash); (self.trie.db().get(&aux_hash).expect("Missing fatdb hash").into_vec(), value) }) - ) + }) } } -#[test] -fn fatdb_to_trie() { +#[cfg(test)] +mod test { use memorydb::MemoryDB; use hashdb::DBValue; - use super::fatdbmut::FatDBMut; - use super::TrieMut; - - let mut memdb = MemoryDB::new(); - let mut root = H256::default(); - { - let mut t = FatDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); + use keccak_hasher::KeccakHasher; + use ethtrie::trie::{Trie, TrieMut}; + use ethtrie::{FatDB, FatDBMut}; + use ethereum_types::H256; + + #[test] + fn fatdb_to_trie() { + let mut memdb = MemoryDB::::new(); + let mut root = H256::new(); + { + let mut t = FatDBMut::new(&mut memdb, &mut root); + t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); + } + let t = FatDB::new(&memdb, &root).unwrap(); + assert_eq!(t.get(&[0x01u8, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0x01u8, 0x23])); + assert_eq!( + t.iter().unwrap().map(Result::unwrap).collect::>(), + vec![(vec![0x01u8, 0x23], DBValue::from_slice(&[0x01u8, 0x23] as &[u8]))]); } - let t = FatDB::new(&memdb, &root).unwrap(); - assert_eq!(t.get(&[0x01u8, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0x01u8, 0x23])); - assert_eq!(t.iter().unwrap().map(Result::unwrap).collect::>(), vec![(vec![0x01u8, 0x23], DBValue::from_slice(&[0x01u8, 0x23] as &[u8]))]); } diff --git a/util/patricia_trie/src/fatdbmut.rs b/util/patricia_trie/src/fatdbmut.rs index 9bf7b880369..67f4f14a75c 100644 --- a/util/patricia_trie/src/fatdbmut.rs +++ b/util/patricia_trie/src/fatdbmut.rs @@ -14,105 +14,116 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use ethereum_types::H256; -use keccak::keccak; -use hashdb::{HashDB, DBValue}; -use super::{TrieDBMut, TrieMut}; +use hashdb::{HashDB, DBValue, Hasher}; +use super::{Result, TrieDBMut, TrieMut}; +use node_codec::NodeCodec; /// A mutable `Trie` implementation which hashes keys and uses a generic `HashDB` backing database. /// Additionaly it stores inserted hash-key mappings for later retrieval. /// /// Use it as a `Trie` or `TrieMut` trait object. -pub struct FatDBMut<'db> { - raw: TrieDBMut<'db>, +pub struct FatDBMut<'db, H, C> +where + H: Hasher + 'db, + C: NodeCodec +{ + raw: TrieDBMut<'db, H, C>, } -impl<'db> FatDBMut<'db> { +impl<'db, H, C> FatDBMut<'db, H, C> +where + H: Hasher, + C: NodeCodec +{ /// Create a new trie with the backing database `db` and empty `root` /// Initialise to the state entailed by the genesis block. /// This guarantees the trie is built correctly. - pub fn new(db: &'db mut HashDB, root: &'db mut H256) -> Self { + pub fn new(db: &'db mut HashDB, root: &'db mut H::Out) -> Self { FatDBMut { raw: TrieDBMut::new(db, root) } } /// Create a new trie with the backing database `db` and `root`. /// /// Returns an error if root does not exist. - pub fn from_existing(db: &'db mut HashDB, root: &'db mut H256) -> super::Result { + pub fn from_existing(db: &'db mut HashDB, root: &'db mut H::Out) -> Result { Ok(FatDBMut { raw: TrieDBMut::from_existing(db, root)? }) } /// Get the backing database. - pub fn db(&self) -> &HashDB { + pub fn db(&self) -> &HashDB { self.raw.db() } /// Get the backing database. - pub fn db_mut(&mut self) -> &mut HashDB { + pub fn db_mut(&mut self) -> &mut HashDB { self.raw.db_mut() } - - fn to_aux_key(key: &[u8]) -> H256 { - keccak(key) - } } -impl<'db> TrieMut for FatDBMut<'db> { - fn root(&mut self) -> &H256 { - self.raw.root() - } +impl<'db, H, C> TrieMut for FatDBMut<'db, H, C> +where + H: Hasher, + C: NodeCodec +{ + fn root(&mut self) -> &H::Out { self.raw.root() } - fn is_empty(&self) -> bool { - self.raw.is_empty() - } + fn is_empty(&self) -> bool { self.raw.is_empty() } - fn contains(&self, key: &[u8]) -> super::Result { - self.raw.contains(&keccak(key)) + fn contains(&self, key: &[u8]) -> Result { + self.raw.contains(H::hash(key).as_ref()) } - fn get<'a, 'key>(&'a self, key: &'key [u8]) -> super::Result> + fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Result, H::Out, C::Error> where 'a: 'key { - self.raw.get(&keccak(key)) + self.raw.get(H::hash(key).as_ref()) } - fn insert(&mut self, key: &[u8], value: &[u8]) -> super::Result> { - let hash = keccak(key); - let out = self.raw.insert(&hash, value)?; + fn insert(&mut self, key: &[u8], value: &[u8]) -> Result, H::Out, C::Error> { + let hash = H::hash(key); + let out = self.raw.insert(hash.as_ref(), value)?; let db = self.raw.db_mut(); // don't insert if it doesn't exist. if out.is_none() { - db.emplace(Self::to_aux_key(&hash), DBValue::from_slice(key)); + let aux_hash = H::hash(hash.as_ref()); + db.emplace(aux_hash, DBValue::from_slice(key)); } Ok(out) } - fn remove(&mut self, key: &[u8]) -> super::Result> { - let hash = keccak(key); - let out = self.raw.remove(&hash)?; + fn remove(&mut self, key: &[u8]) -> Result, H::Out, C::Error> { + let hash = H::hash(key); + let out = self.raw.remove(hash.as_ref())?; // don't remove if it already exists. if out.is_some() { - self.raw.db_mut().remove(&Self::to_aux_key(&hash)); + self.raw.db_mut().remove(&hash); } Ok(out) } } -#[test] -fn fatdb_to_trie() { +#[cfg(test)] +mod test { + use hashdb::DBValue; use memorydb::MemoryDB; - use super::TrieDB; - use super::Trie; - - let mut memdb = MemoryDB::new(); - let mut root = H256::default(); - { - let mut t = FatDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); + use ethtrie::trie::{Trie, TrieMut}; + use ethtrie::{TrieDB, FatDBMut}; + use keccak_hasher::KeccakHasher; + use keccak; + use ethereum_types::H256; + + #[test] + fn fatdbmut_to_trie() { + let mut memdb = MemoryDB::::new(); + let mut root = H256::new(); + { + let mut t = FatDBMut::new(&mut memdb, &mut root); + t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); + } + let t = TrieDB::new(&memdb, &root).unwrap(); + assert_eq!(t.get(&keccak::keccak(&[0x01u8, 0x23])).unwrap().unwrap(), DBValue::from_slice(&[0x01u8, 0x23])); } - let t = TrieDB::new(&memdb, &root).unwrap(); - assert_eq!(t.get(&keccak(&[0x01u8, 0x23])).unwrap().unwrap(), DBValue::from_slice(&[0x01u8, 0x23])); -} +} \ No newline at end of file diff --git a/util/patricia_trie/src/lib.rs b/util/patricia_trie/src/lib.rs index 8e0e44f032f..a028be87ac9 100644 --- a/util/patricia_trie/src/lib.rs +++ b/util/patricia_trie/src/lib.rs @@ -15,26 +15,36 @@ // along with Parity. If not, see . //! Trie interface and implementation. -extern crate rand; -extern crate ethereum_types; -extern crate keccak_hash as keccak; -extern crate rlp; -extern crate hashdb; -extern crate ethcore_bytes as bytes; extern crate elastic_array; -extern crate memorydb; -extern crate ethcore_logger; +extern crate ethcore_bytes as bytes; +extern crate hashdb; +extern crate heapsize; +extern crate rand; +#[macro_use] +extern crate log; +#[cfg(test)] +extern crate env_logger; +#[cfg(test)] +extern crate ethereum_types; #[cfg(test)] extern crate trie_standardmap as standardmap; - -#[macro_use] -extern crate log; +#[cfg(test)] +extern crate patricia_trie_ethereum as ethtrie; +#[cfg(test)] +extern crate memorydb; +#[cfg(test)] +extern crate rlp; +#[cfg(test)] +extern crate keccak_hash as keccak; +#[cfg(test)] +extern crate keccak_hasher; +#[cfg(test)] +extern crate triehash; use std::{fmt, error}; -use ethereum_types::H256; -use keccak::KECCAK_NULL_RLP; -use hashdb::{HashDB, DBValue}; +use hashdb::{HashDB, DBValue, Hasher}; +use std::marker::PhantomData; pub mod node; pub mod triedb; @@ -46,158 +56,154 @@ pub mod recorder; mod fatdb; mod fatdbmut; mod lookup; -mod nibbleslice; mod nibblevec; +mod nibbleslice; +mod node_codec; -pub use self::triedbmut::TrieDBMut; pub use self::triedb::{TrieDB, TrieDBIterator}; +pub use self::triedbmut::{TrieDBMut, ChildReference}; pub use self::sectriedbmut::SecTrieDBMut; pub use self::sectriedb::SecTrieDB; pub use self::fatdb::{FatDB, FatDBIterator}; pub use self::fatdbmut::FatDBMut; pub use self::recorder::Recorder; +pub use self::lookup::Lookup; +pub use self::nibbleslice::NibbleSlice; +pub use node_codec::NodeCodec; /// Trie Errors. /// /// These borrow the data within them to avoid excessive copying on every /// trie operation. #[derive(Debug, PartialEq, Eq, Clone)] -pub enum TrieError { +pub enum TrieError { /// Attempted to create a trie with a state root not in the DB. - InvalidStateRoot(H256), + InvalidStateRoot(T), /// Trie item not found in the database, - IncompleteDatabase(H256), + IncompleteDatabase(T), /// Corrupt Trie item - DecoderError(rlp::DecoderError), + DecoderError(T, E), } -impl fmt::Display for TrieError { +impl fmt::Display for TrieError where T: std::fmt::Debug, E: std::fmt::Debug { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - TrieError::InvalidStateRoot(ref root) => write!(f, "Invalid state root: {}", root), - TrieError::IncompleteDatabase(ref missing) => - write!(f, "Database missing expected key: {}", missing), - TrieError::DecoderError(ref err) => write!(f, "Decoding failed with {}", err), + TrieError::InvalidStateRoot(ref root) => write!(f, "Invalid state root: {:?}", root), + TrieError::IncompleteDatabase(ref missing) => write!(f, "Database missing expected key: {:?}", missing), + TrieError::DecoderError(ref hash, ref decoder_err) => write!(f, "Decoding failed for hash {:?}; err: {:?}", hash, decoder_err), } } } -impl error::Error for TrieError { +impl error::Error for TrieError where T: std::fmt::Debug, E: std::error::Error { fn description(&self) -> &str { match *self { TrieError::InvalidStateRoot(_) => "Invalid state root", TrieError::IncompleteDatabase(_) => "Incomplete database", - TrieError::DecoderError(ref e) => e.description(), + TrieError::DecoderError(_, ref err) => err.description(), } } } -impl From for Box { - fn from(e: rlp::DecoderError) -> Self { Box::new(TrieError::DecoderError(e)) } -} +/// Trie result type. Boxed to avoid copying around extra space for the `Hasher`s `Out` on successful queries. +pub type Result = ::std::result::Result>>; -/// Trie result type. Boxed to avoid copying around extra space for `H256`s on successful queries. -pub type Result = ::std::result::Result>; -/// Trie-Item type. -pub type TrieItem<'a> = Result<(Vec, DBValue)>; +/// Trie-Item type used for iterators over trie data. +pub type TrieItem<'a, U, E> = Result<(Vec, DBValue), U, E>; /// Description of what kind of query will be made to the trie. /// /// This is implemented for any &mut recorder (where the query will return /// a DBValue), any function taking raw bytes (where no recording will be made), /// or any tuple of (&mut Recorder, FnOnce(&[u8])) -pub trait Query { +pub trait Query { /// Output item. type Item; /// Decode a byte-slice into the desired item. - fn decode(self, &[u8]) -> Self::Item; + fn decode(self, data: &[u8]) -> Self::Item; /// Record that a node has been passed through. - fn record(&mut self, &H256, &[u8], u32) { } + fn record(&mut self, _hash: &H::Out, _data: &[u8], _depth: u32) {} } -impl<'a> Query for &'a mut Recorder { +impl<'a, H: Hasher> Query for &'a mut Recorder { type Item = DBValue; - fn decode(self, value: &[u8]) -> DBValue { DBValue::from_slice(value) } - fn record(&mut self, hash: &H256, data: &[u8], depth: u32) { + fn record(&mut self, hash: &H::Out, data: &[u8], depth: u32) { (&mut **self).record(hash, data, depth); } } -impl Query for F where F: for<'a> FnOnce(&'a [u8]) -> T { +impl Query for F where F: for<'a> FnOnce(&'a [u8]) -> T { type Item = T; - fn decode(self, value: &[u8]) -> T { (self)(value) } } -impl<'a, F, T> Query for (&'a mut Recorder, F) where F: FnOnce(&[u8]) -> T { +impl<'a, F, T, H: Hasher> Query for (&'a mut Recorder, F) where F: FnOnce(&[u8]) -> T { type Item = T; - fn decode(self, value: &[u8]) -> T { (self.1)(value) } - fn record(&mut self, hash: &H256, data: &[u8], depth: u32) { + fn record(&mut self, hash: &H::Out, data: &[u8], depth: u32) { self.0.record(hash, data, depth) } } /// A key-value datastore implemented as a database-backed modified Merkle tree. -pub trait Trie { +pub trait Trie> { /// Return the root of the trie. - fn root(&self) -> &H256; + fn root(&self) -> &H::Out; /// Is the trie empty? - fn is_empty(&self) -> bool { *self.root() == KECCAK_NULL_RLP } + fn is_empty(&self) -> bool { *self.root() == C::HASHED_NULL_NODE } /// Does the trie contain a given key? - fn contains(&self, key: &[u8]) -> Result { - self.get(key).map(|x| x.is_some()) + fn contains(&self, key: &[u8]) -> Result { + self.get(key).map(|x|x.is_some() ) } /// What is the value of the given key in this trie? - fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Result> where 'a: 'key { + fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Result, H::Out, C::Error> where 'a: 'key { self.get_with(key, DBValue::from_slice) } /// Search for the key with the given query parameter. See the docs of the `Query` /// trait for more details. - fn get_with<'a, 'key, Q: Query>(&'a self, key: &'key [u8], query: Q) - -> Result> where 'a: 'key; + fn get_with<'a, 'key, Q: Query>(&'a self, key: &'key [u8], query: Q) -> Result, H::Out, C::Error> where 'a: 'key; /// Returns a depth-first iterator over the elements of trie. - fn iter<'a>(&'a self) -> Result + 'a>>; + fn iter<'a>(&'a self) -> Result> + 'a>, H::Out, C::Error>; } /// A key-value datastore implemented as a database-backed modified Merkle tree. -pub trait TrieMut { +pub trait TrieMut> { /// Return the root of the trie. - fn root(&mut self) -> &H256; + fn root(&mut self) -> &H::Out; /// Is the trie empty? fn is_empty(&self) -> bool; /// Does the trie contain a given key? - fn contains(&self, key: &[u8]) -> Result { + fn contains(&self, key: &[u8]) -> Result { self.get(key).map(|x| x.is_some()) } /// What is the value of the given key in this trie? - fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Result> where 'a: 'key; + fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Result, H::Out, C::Error> where 'a: 'key; /// Insert a `key`/`value` pair into the trie. An empty value is equivalent to removing /// `key` from the trie. Returns the old value associated with this key, if it existed. - fn insert(&mut self, key: &[u8], value: &[u8]) -> Result>; + fn insert(&mut self, key: &[u8], value: &[u8]) -> Result, H::Out, C::Error>; /// Remove a `key` from the trie. Equivalent to making it equal to the empty /// value. Returns the old value associated with this key, if it existed. - fn remove(&mut self, key: &[u8]) -> Result>; + fn remove(&mut self, key: &[u8]) -> Result, H::Out, C::Error>; } -/// A trie iterator that also supports random access. -pub trait TrieIterator : Iterator { +/// A trie iterator that also supports random access (`seek()`). +pub trait TrieIterator>: Iterator { /// Position the iterator on the first element with key > `key` - fn seek(&mut self, key: &[u8]) -> Result<()>; + fn seek(&mut self, key: &[u8]) -> Result<(), H::Out, >::Error>; } /// Trie types @@ -219,19 +225,21 @@ impl Default for TrieSpec { /// Trie factory. #[derive(Default, Clone)] -pub struct TrieFactory { +pub struct TrieFactory> { spec: TrieSpec, + mark_hash: PhantomData, + mark_codec: PhantomData, } /// All different kinds of tries. /// This is used to prevent a heap allocation for every created trie. -pub enum TrieKinds<'db> { +pub enum TrieKinds<'db, H: Hasher + 'db, C: NodeCodec> { /// A generic trie db. - Generic(TrieDB<'db>), + Generic(TrieDB<'db, H, C>), /// A secure trie db. - Secure(SecTrieDB<'db>), + Secure(SecTrieDB<'db, H, C>), /// A fat trie db. - Fat(FatDB<'db>), + Fat(FatDB<'db, H, C>), } // wrapper macro for making the match easier to deal with. @@ -245,8 +253,8 @@ macro_rules! wrapper { } } -impl<'db> Trie for TrieKinds<'db> { - fn root(&self) -> &H256 { +impl<'db, H: Hasher, C: NodeCodec> Trie for TrieKinds<'db, H, C> { + fn root(&self) -> &H::Out { wrapper!(self, root,) } @@ -254,31 +262,33 @@ impl<'db> Trie for TrieKinds<'db> { wrapper!(self, is_empty,) } - fn contains(&self, key: &[u8]) -> Result { + fn contains(&self, key: &[u8]) -> Result { wrapper!(self, contains, key) } - fn get_with<'a, 'key, Q: Query>(&'a self, key: &'key [u8], query: Q) -> Result> + fn get_with<'a, 'key, Q: Query>(&'a self, key: &'key [u8], query: Q) -> Result, H::Out, C::Error> where 'a: 'key { wrapper!(self, get_with, key, query) } - fn iter<'a>(&'a self) -> Result + 'a>> { + fn iter<'a>(&'a self) -> Result> + 'a>, H::Out, C::Error> { wrapper!(self, iter,) } } -impl TrieFactory { +impl<'db, H, C> TrieFactory +where + H: Hasher, + C: NodeCodec + 'db +{ /// Creates new factory. pub fn new(spec: TrieSpec) -> Self { - TrieFactory { - spec: spec, - } + TrieFactory { spec, mark_hash: PhantomData, mark_codec: PhantomData } } /// Create new immutable instance of Trie. - pub fn readonly<'db>(&self, db: &'db HashDB, root: &'db H256) -> Result> { + pub fn readonly(&self, db: &'db HashDB, root: &'db H::Out) -> Result, H::Out, >::Error> { match self.spec { TrieSpec::Generic => Ok(TrieKinds::Generic(TrieDB::new(db, root)?)), TrieSpec::Secure => Ok(TrieKinds::Secure(SecTrieDB::new(db, root)?)), @@ -287,20 +297,20 @@ impl TrieFactory { } /// Create new mutable instance of Trie. - pub fn create<'db>(&self, db: &'db mut HashDB, root: &'db mut H256) -> Box { + pub fn create(&self, db: &'db mut HashDB, root: &'db mut H::Out) -> Box + 'db> { match self.spec { - TrieSpec::Generic => Box::new(TrieDBMut::new(db, root)), - TrieSpec::Secure => Box::new(SecTrieDBMut::new(db, root)), - TrieSpec::Fat => Box::new(FatDBMut::new(db, root)), + TrieSpec::Generic => Box::new(TrieDBMut::<_, C>::new(db, root)), + TrieSpec::Secure => Box::new(SecTrieDBMut::<_, C>::new(db, root)), + TrieSpec::Fat => Box::new(FatDBMut::<_, C>::new(db, root)), } } /// Create new mutable instance of trie and check for errors. - pub fn from_existing<'db>(&self, db: &'db mut HashDB, root: &'db mut H256) -> Result> { + pub fn from_existing(&self, db: &'db mut HashDB, root: &'db mut H::Out) -> Result + 'db>, H::Out, >::Error> { match self.spec { - TrieSpec::Generic => Ok(Box::new(TrieDBMut::from_existing(db, root)?)), - TrieSpec::Secure => Ok(Box::new(SecTrieDBMut::from_existing(db, root)?)), - TrieSpec::Fat => Ok(Box::new(FatDBMut::from_existing(db, root)?)), + TrieSpec::Generic => Ok(Box::new(TrieDBMut::<_, C>::from_existing(db, root)?)), + TrieSpec::Secure => Ok(Box::new(SecTrieDBMut::<_, C>::from_existing(db, root)?)), + TrieSpec::Fat => Ok(Box::new(FatDBMut::<_, C>::from_existing(db, root)?)), } } diff --git a/util/patricia_trie/src/lookup.rs b/util/patricia_trie/src/lookup.rs index ae91689a311..6e9c7ff75fb 100644 --- a/util/patricia_trie/src/lookup.rs +++ b/util/patricia_trie/src/lookup.rs @@ -16,27 +16,33 @@ //! Trie lookup via HashDB. -use hashdb::HashDB; +use hashdb::{HashDB, Hasher}; use nibbleslice::NibbleSlice; -use ethereum_types::H256; - -use super::{TrieError, Query}; -use super::node::Node; +use node::Node; +use node_codec::NodeCodec; +use super::{Result, TrieError, Query}; +use std::marker::PhantomData; /// Trie lookup helper object. -pub struct Lookup<'a, Q: Query> { +pub struct Lookup<'a, H: Hasher + 'a, C: NodeCodec, Q: Query> { /// database to query from. - pub db: &'a HashDB, + pub db: &'a HashDB, /// Query object to record nodes and transform data. pub query: Q, /// Hash to start at - pub hash: H256, + pub hash: H::Out, + pub marker: PhantomData, // TODO: probably not needed when all is said and done? When Query is made generic? } -impl<'a, Q: Query> Lookup<'a, Q> { +impl<'a, H, C, Q> Lookup<'a, H, C, Q> +where + H: Hasher + 'a, + C: NodeCodec + 'a, + Q: Query, +{ /// Look up the given key. If the value is found, it will be passed to the given /// function to decode or copy. - pub fn look_up(mut self, mut key: NibbleSlice) -> super::Result> { + pub fn look_up(mut self, mut key: NibbleSlice) -> Result, H::Out, C::Error> { let mut hash = self.hash; // this loop iterates through non-inline nodes. @@ -55,7 +61,13 @@ impl<'a, Q: Query> Lookup<'a, Q> { // without incrementing the depth. let mut node_data = &node_data[..]; loop { - match Node::decoded(node_data)? { + let decoded = match C::decode(node_data) { + Ok(node) => node, + Err(e) => { + return Err(Box::new(TrieError::DecoderError(hash, e))) + } + }; + match decoded { Node::Leaf(slice, value) => { return Ok(match slice == key { true => Some(self.query.decode(value)), @@ -81,7 +93,7 @@ impl<'a, Q: Query> Lookup<'a, Q> { } // check if new node data is inline or hash. - if let Some(h) = Node::try_decode_hash(&node_data) { + if let Some(h) = C::try_decode_hash(&node_data) { hash = h; break } diff --git a/util/patricia_trie/src/nibbleslice.rs b/util/patricia_trie/src/nibbleslice.rs index 8cb03e53dd6..b87a6636974 100644 --- a/util/patricia_trie/src/nibbleslice.rs +++ b/util/patricia_trie/src/nibbleslice.rs @@ -105,9 +105,11 @@ impl<'a> NibbleSlice<'a> { pub fn is_empty(&self) -> bool { self.len() == 0 } /// Get the length (in nibbles, naturally) of this slice. + #[inline] pub fn len(&self) -> usize { (self.data.len() + self.data_encode_suffix.len()) * 2 - self.offset - self.offset_encode_suffix } /// Get the nibble at position `i`. + #[inline(always)] pub fn at(&self, i: usize) -> u8 { let l = self.data.len() * 2 - self.offset; if i < l { @@ -154,6 +156,7 @@ impl<'a> NibbleSlice<'a> { } /// Encode while nibble slice in prefixed hex notation, noting whether it `is_leaf`. + #[inline] pub fn encoded(&self, is_leaf: bool) -> ElasticArray36 { let l = self.len(); let mut r = ElasticArray36::new(); diff --git a/util/patricia_trie/src/nibblevec.rs b/util/patricia_trie/src/nibblevec.rs index 4398dbc6f7e..3fe8c9fb75c 100644 --- a/util/patricia_trie/src/nibblevec.rs +++ b/util/patricia_trie/src/nibblevec.rs @@ -41,12 +41,14 @@ impl NibbleVec { } /// Length of the `NibbleVec` + #[inline(always)] pub fn len(&self) -> usize { self.len } /// Retrurns true if `NibbleVec` has zero length pub fn is_empty(&self) -> bool { self.len == 0 } /// Try to get the nibble at the given offset. + #[inline] pub fn at(&self, idx: usize) -> u8 { if idx % 2 == 0 { self.inner[idx / 2] >> 4 diff --git a/util/patricia_trie/src/node.rs b/util/patricia_trie/src/node.rs index 0ded1f66dbc..72c344fc3ae 100644 --- a/util/patricia_trie/src/node.rs +++ b/util/patricia_trie/src/node.rs @@ -14,12 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use ethereum_types::H256; use elastic_array::ElasticArray36; use nibbleslice::NibbleSlice; use nibblevec::NibbleVec; -use bytes::*; -use rlp::{Rlp, RlpStream, Prototype, DecoderError}; use hashdb::DBValue; /// Partial node key type. @@ -35,83 +32,7 @@ pub enum Node<'a> { /// Extension node; has key slice and node data. Data may not be null. Extension(NibbleSlice<'a>, &'a [u8]), /// Branch node; has array of 16 child nodes (each possibly null) and an optional immediate node data. - Branch([&'a [u8]; 16], Option<&'a [u8]>) -} - -impl<'a> Node<'a> { - /// Decode the `node_rlp` and return the Node. - pub fn decoded(node_rlp: &'a [u8]) -> Result { - let r = Rlp::new(node_rlp); - match r.prototype()? { - // either leaf or extension - decode first item with NibbleSlice::??? - // and use is_leaf return to figure out which. - // if leaf, second item is a value (is_data()) - // if extension, second item is a node (either SHA3 to be looked up and - // fed back into this function or inline RLP which can be fed back into this function). - Prototype::List(2) => match NibbleSlice::from_encoded(r.at(0)?.data()?) { - (slice, true) => Ok(Node::Leaf(slice, r.at(1)?.data()?)), - (slice, false) => Ok(Node::Extension(slice, r.at(1)?.as_raw())), - }, - // branch - first 16 are nodes, 17th is a value (or empty). - Prototype::List(17) => { - let mut nodes = [&[] as &[u8]; 16]; - for i in 0..16 { - nodes[i] = r.at(i)?.as_raw(); - } - Ok(Node::Branch(nodes, if r.at(16)?.is_empty() { None } else { Some(r.at(16)?.data()?) })) - }, - // an empty branch index. - Prototype::Data(0) => Ok(Node::Empty), - // something went wrong. - _ => Err(DecoderError::Custom("Rlp is not valid.")) - } - } - - /// Encode the node into RLP. - /// - /// Will always return the direct node RLP even if it's 32 or more bytes. To get the - /// RLP which would be valid for using in another node, use `encoded_and_added()`. - pub fn encoded(&self) -> Bytes { - match *self { - Node::Leaf(ref slice, ref value) => { - let mut stream = RlpStream::new_list(2); - stream.append(&&*slice.encoded(true)); - stream.append(value); - stream.out() - }, - Node::Extension(ref slice, ref raw_rlp) => { - let mut stream = RlpStream::new_list(2); - stream.append(&&*slice.encoded(false)); - stream.append_raw(raw_rlp, 1); - stream.out() - }, - Node::Branch(ref nodes, ref value) => { - let mut stream = RlpStream::new_list(17); - for i in 0..16 { - stream.append_raw(nodes[i], 1); - } - match *value { - Some(ref n) => { stream.append(n); }, - None => { stream.append_empty_data(); }, - } - stream.out() - }, - Node::Empty => { - let mut stream = RlpStream::new(); - stream.append_empty_data(); - stream.out() - } - } - } - - pub fn try_decode_hash(node_data: &[u8]) -> Option { - let r = Rlp::new(node_data); - if r.is_data() && r.size() == 32 { - Some(r.as_val().expect("Hash is the correct size of 32 bytes; qed")) - } else { - None - } - } + Branch([&'a [u8]; 16], Option<&'a [u8]>), } /// An owning node type. Useful for trie iterators. diff --git a/util/patricia_trie/src/node_codec.rs b/util/patricia_trie/src/node_codec.rs new file mode 100644 index 00000000000..1dec20f90f5 --- /dev/null +++ b/util/patricia_trie/src/node_codec.rs @@ -0,0 +1,55 @@ +// Copyright 2015-2018 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Generic trait for trie node encoding/decoding. Takes a `hashdb::Hasher` +//! to parametrize the hashes used in the codec. + +use hashdb::Hasher; +use node::Node; +use ChildReference; + +use elastic_array::{ElasticArray1024, ElasticArray128}; + +/// Trait for trie node encoding/decoding +pub trait NodeCodec: Sized { + /// Encoding error type + type Error: ::std::error::Error; + + /// Null node type + const HASHED_NULL_NODE: H::Out; + + /// Decode bytes to a `Node`. Returns `Self::E` on failure. + fn decode(data: &[u8]) -> Result; + + /// Decode bytes to the `Hasher`s output type. Returns `None` on failure. + fn try_decode_hash(data: &[u8]) -> Option; + + /// Check if the provided bytes correspond to the codecs "empty" node. + fn is_empty_node(data: &[u8]) -> bool; + + /// Returns an empty node + fn empty_node() -> ElasticArray1024; + + /// Returns an encoded leaft node + fn leaf_node(partial: &[u8], value: &[u8]) -> ElasticArray1024; + + /// Returns an encoded extension node + fn ext_node(partial: &[u8], child_ref: ChildReference) -> ElasticArray1024; + + /// Returns an encoded branch node. Takes an iterator yielding `ChildReference` and an optional value + fn branch_node(children: I, value: Option>) -> ElasticArray1024 + where I: IntoIterator>>; +} diff --git a/util/patricia_trie/src/recorder.rs b/util/patricia_trie/src/recorder.rs index 6a0f9b45ebe..9ad7d8c3309 100644 --- a/util/patricia_trie/src/recorder.rs +++ b/util/patricia_trie/src/recorder.rs @@ -16,13 +16,11 @@ //! Trie query recorder. -use keccak::keccak; -use ethereum_types::H256; use bytes::Bytes; /// A record of a visited node. #[derive(PartialEq, Eq, Debug, Clone)] -pub struct Record { +pub struct Record { /// The depth of this node. pub depth: u32, @@ -30,23 +28,23 @@ pub struct Record { pub data: Bytes, /// The hash of the data. - pub hash: H256, + pub hash: HO, } /// Records trie nodes as they pass it. #[derive(Debug)] -pub struct Recorder { - nodes: Vec, +pub struct Recorder { + nodes: Vec>, min_depth: u32, } -impl Default for Recorder { +impl Default for Recorder { fn default() -> Self { Recorder::new() } } -impl Recorder { +impl Recorder { /// Create a new `Recorder` which records all given nodes. #[inline] pub fn new() -> Self { @@ -62,9 +60,7 @@ impl Recorder { } /// Record a visited node, given its hash, data, and depth. - pub fn record(&mut self, hash: &H256, data: &[u8], depth: u32) { - debug_assert_eq!(keccak(data), *hash); - + pub fn record(&mut self, hash: &HO, data: &[u8], depth: u32) { if depth >= self.min_depth { self.nodes.push(Record { depth: depth, @@ -75,7 +71,7 @@ impl Recorder { } /// Drain all visited records. - pub fn drain(&mut self) -> Vec { + pub fn drain(&mut self) -> Vec> { ::std::mem::replace(&mut self.nodes, Vec::new()) } } @@ -83,11 +79,13 @@ impl Recorder { #[cfg(test)] mod tests { use super::*; + use keccak::keccak; + use keccak_hasher::KeccakHasher; use ethereum_types::H256; #[test] fn basic_recorder() { - let mut basic = Recorder::new(); + let mut basic = Recorder::::new(); let node1 = vec![1, 2, 3, 4]; let node2 = vec![4, 5, 6, 7, 8, 9, 10]; @@ -105,15 +103,16 @@ mod tests { let record2 = Record { data: node2, hash: hash2, - depth: 456 + depth: 456, }; + assert_eq!(basic.drain(), vec![record1, record2]); } #[test] fn basic_recorder_min_depth() { - let mut basic = Recorder::with_depth(400); + let mut basic = Recorder::::with_depth(400); let node1 = vec![1, 2, 3, 4]; let node2 = vec![4, 5, 6, 7, 8, 9, 10]; @@ -136,10 +135,11 @@ mod tests { #[test] fn trie_record() { - use super::super::{TrieDB, TrieDBMut, Trie, TrieMut}; + use ethtrie::trie::{Trie, TrieMut, Recorder}; use memorydb::MemoryDB; + use ethtrie::{TrieDB, TrieDBMut}; - let mut db = MemoryDB::new(); + let mut db = MemoryDB::::new(); let mut root = H256::default(); @@ -157,7 +157,7 @@ mod tests { } let trie = TrieDB::new(&db, &root).unwrap(); - let mut recorder = Recorder::new(); + let mut recorder = Recorder::::new(); trie.get_with(b"pirate", &mut recorder).unwrap().unwrap(); diff --git a/util/patricia_trie/src/sectriedb.rs b/util/patricia_trie/src/sectriedb.rs index c8d5ec0ec8f..a340de947be 100644 --- a/util/patricia_trie/src/sectriedb.rs +++ b/util/patricia_trie/src/sectriedb.rs @@ -14,71 +14,87 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use ethereum_types::H256; -use keccak::keccak; -use hashdb::HashDB; +use hashdb::{HashDB, Hasher}; use super::triedb::TrieDB; -use super::{Trie, TrieItem, TrieIterator, Query}; +use super::{Result, Trie, TrieItem, TrieIterator, Query}; +use node_codec::NodeCodec; /// A `Trie` implementation which hashes keys and uses a generic `HashDB` backing database. /// /// Use it as a `Trie` trait object. You can use `raw()` to get the backing `TrieDB` object. -pub struct SecTrieDB<'db> { - raw: TrieDB<'db> +pub struct SecTrieDB<'db, H, C> +where + H: Hasher + 'db, + C: NodeCodec +{ + raw: TrieDB<'db, H, C> } -impl<'db> SecTrieDB<'db> { +impl<'db, H, C> SecTrieDB<'db, H, C> +where + H: Hasher, + C: NodeCodec +{ /// Create a new trie with the backing database `db` and empty `root` /// /// Initialise to the state entailed by the genesis block. /// This guarantees the trie is built correctly. /// Returns an error if root does not exist. - pub fn new(db: &'db HashDB, root: &'db H256) -> super::Result { + pub fn new(db: &'db HashDB, root: &'db H::Out) -> Result { Ok(SecTrieDB { raw: TrieDB::new(db, root)? }) } /// Get a reference to the underlying raw `TrieDB` struct. - pub fn raw(&self) -> &TrieDB { + pub fn raw(&self) -> &TrieDB { &self.raw } /// Get a mutable reference to the underlying raw `TrieDB` struct. - pub fn raw_mut(&mut self) -> &mut TrieDB<'db> { + pub fn raw_mut(&mut self) -> &mut TrieDB<'db, H, C> { &mut self.raw } } -impl<'db> Trie for SecTrieDB<'db> { - fn iter<'a>(&'a self) -> super::Result + 'a>> { - TrieDB::iter(&self.raw) - } +impl<'db, H, C> Trie for SecTrieDB<'db, H, C> +where + H: Hasher, + C: NodeCodec +{ + fn root(&self) -> &H::Out { self.raw.root() } - fn root(&self) -> &H256 { self.raw.root() } - - fn contains(&self, key: &[u8]) -> super::Result { - self.raw.contains(&keccak(key)) + fn contains(&self, key: &[u8]) -> Result { + self.raw.contains(H::hash(key).as_ref()) } - fn get_with<'a, 'key, Q: Query>(&'a self, key: &'key [u8], query: Q) -> super::Result> + fn get_with<'a, 'key, Q: Query>(&'a self, key: &'key [u8], query: Q) -> Result, H::Out, C::Error> where 'a: 'key { - self.raw.get_with(&keccak(key), query) + self.raw.get_with(H::hash(key).as_ref(), query) + } + + fn iter<'a>(&'a self) -> Result> + 'a>, H::Out, C::Error> { + TrieDB::iter(&self.raw) } } -#[test] -fn trie_to_sectrie() { +#[cfg(test)] +mod test { use memorydb::MemoryDB; use hashdb::DBValue; - use super::triedbmut::TrieDBMut; - use super::TrieMut; + use keccak; + use keccak_hasher::KeccakHasher; + use ethtrie::{TrieDBMut, SecTrieDB, trie::{Trie, TrieMut}}; + use ethereum_types::H256; - let mut memdb = MemoryDB::new(); - let mut root = H256::default(); - { - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(&keccak(&[0x01u8, 0x23]), &[0x01u8, 0x23]).unwrap(); + #[test] + fn trie_to_sectrie() { + let mut db = MemoryDB::::new(); + let mut root = H256::new(); + { + let mut t = TrieDBMut::new(&mut db, &mut root); + t.insert(&keccak::keccak(&[0x01u8, 0x23]), &[0x01u8, 0x23]).unwrap(); + } + let t = SecTrieDB::new(&db, &root).unwrap(); + assert_eq!(t.get(&[0x01u8, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0x01u8, 0x23])); } - let t = SecTrieDB::new(&memdb, &root).unwrap(); - assert_eq!(t.get(&[0x01u8, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0x01u8, 0x23])); -} +} \ No newline at end of file diff --git a/util/patricia_trie/src/sectriedbmut.rs b/util/patricia_trie/src/sectriedbmut.rs index 335fb2f1835..8750c2dd5c1 100644 --- a/util/patricia_trie/src/sectriedbmut.rs +++ b/util/patricia_trie/src/sectriedbmut.rs @@ -14,43 +14,53 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use ethereum_types::H256; -use keccak::keccak; -use hashdb::{HashDB, DBValue}; -use super::triedbmut::TrieDBMut; -use super::TrieMut; +use hashdb::{HashDB, DBValue, Hasher}; +use super::{Result, TrieMut, TrieDBMut}; +use node_codec::NodeCodec; /// A mutable `Trie` implementation which hashes keys and uses a generic `HashDB` backing database. /// /// Use it as a `Trie` or `TrieMut` trait object. You can use `raw()` to get the backing `TrieDBMut` object. -pub struct SecTrieDBMut<'db> { - raw: TrieDBMut<'db> +pub struct SecTrieDBMut<'db, H, C> +where + H: Hasher + 'db, + C: NodeCodec +{ + raw: TrieDBMut<'db, H, C> } -impl<'db> SecTrieDBMut<'db> { +impl<'db, H, C> SecTrieDBMut<'db, H, C> +where + H: Hasher, + C: NodeCodec +{ /// Create a new trie with the backing database `db` and empty `root` /// Initialise to the state entailed by the genesis block. /// This guarantees the trie is built correctly. - pub fn new(db: &'db mut HashDB, root: &'db mut H256) -> Self { + pub fn new(db: &'db mut HashDB, root: &'db mut H::Out) -> Self { SecTrieDBMut { raw: TrieDBMut::new(db, root) } } /// Create a new trie with the backing database `db` and `root`. /// /// Returns an error if root does not exist. - pub fn from_existing(db: &'db mut HashDB, root: &'db mut H256) -> super::Result { + pub fn from_existing(db: &'db mut HashDB, root: &'db mut H::Out) -> Result { Ok(SecTrieDBMut { raw: TrieDBMut::from_existing(db, root)? }) } /// Get the backing database. - pub fn db(&self) -> &HashDB { self.raw.db() } + pub fn db(&self) -> &HashDB { self.raw.db() } /// Get the backing database. - pub fn db_mut(&mut self) -> &mut HashDB { self.raw.db_mut() } + pub fn db_mut(&mut self) -> &mut HashDB { self.raw.db_mut() } } -impl<'db> TrieMut for SecTrieDBMut<'db> { - fn root(&mut self) -> &H256 { +impl<'db, H, C> TrieMut for SecTrieDBMut<'db, H, C> +where + H: Hasher, + C: NodeCodec +{ + fn root(&mut self) -> &H::Out { self.raw.root() } @@ -58,37 +68,43 @@ impl<'db> TrieMut for SecTrieDBMut<'db> { self.raw.is_empty() } - fn contains(&self, key: &[u8]) -> super::Result { - self.raw.contains(&keccak(key)) + fn contains(&self, key: &[u8]) -> Result { + self.raw.contains(&H::hash(key).as_ref()) } - fn get<'a, 'key>(&'a self, key: &'key [u8]) -> super::Result> + fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Result, H::Out, C::Error> where 'a: 'key { - self.raw.get(&keccak(key)) + self.raw.get(&H::hash(key).as_ref()) } - fn insert(&mut self, key: &[u8], value: &[u8]) -> super::Result> { - self.raw.insert(&keccak(key), value) + fn insert(&mut self, key: &[u8], value: &[u8]) -> Result, H::Out, C::Error> { + self.raw.insert(&H::hash(key).as_ref(), value) } - fn remove(&mut self, key: &[u8]) -> super::Result> { - self.raw.remove(&keccak(key)) + fn remove(&mut self, key: &[u8]) -> Result, H::Out, C::Error> { + self.raw.remove(&H::hash(key).as_ref()) } } -#[test] -fn sectrie_to_trie() { - use memorydb::*; - use super::triedb::*; - use super::Trie; - - let mut memdb = MemoryDB::new(); - let mut root = H256::default(); - { - let mut t = SecTrieDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); +#[cfg(test)] +mod test { + use memorydb::MemoryDB; + use hashdb::DBValue; + use keccak; + use keccak_hasher::KeccakHasher; + use ethtrie::{TrieDB, SecTrieDBMut, trie::{Trie, TrieMut}}; + use ethereum_types::H256; + + #[test] + fn sectrie_to_trie() { + let mut memdb = MemoryDB::::new(); + let mut root = H256::new(); + { + let mut t = SecTrieDBMut::new(&mut memdb, &mut root); + t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); + } + let t = TrieDB::new(&memdb, &root).unwrap(); + assert_eq!(t.get(&keccak::keccak(&[0x01u8, 0x23])).unwrap().unwrap(), DBValue::from_slice(&[0x01u8, 0x23])); } - let t = TrieDB::new(&memdb, &root).unwrap(); - assert_eq!(t.get(&keccak(&[0x01u8, 0x23])).unwrap().unwrap(), DBValue::from_slice(&[0x01u8, 0x23])); } diff --git a/util/patricia_trie/src/triedb.rs b/util/patricia_trie/src/triedb.rs index 65ce3caba8a..bf88ab2ec2f 100644 --- a/util/patricia_trie/src/triedb.rs +++ b/util/patricia_trie/src/triedb.rs @@ -18,12 +18,15 @@ use std::fmt; use hashdb::*; use nibbleslice::NibbleSlice; use super::node::{Node, OwnedNode}; +use node_codec::NodeCodec; use super::lookup::Lookup; -use super::{Trie, TrieItem, TrieError, TrieIterator, Query}; -use ethereum_types::H256; +use super::{Result, Trie, TrieItem, TrieError, TrieIterator, Query}; use bytes::Bytes; +use std::marker::PhantomData; -/// A `Trie` implementation using a generic `HashDB` backing database. +/// A `Trie` implementation using a generic `HashDB` backing database, a `Hasher` +/// implementation to generate keys and a `NodeCodec` implementation to encode/decode +/// the nodes. /// /// Use it as a `Trie` trait object. You can use `db()` to get the backing database object. /// Use `get` and `contains` to query values associated with keys in the trie. @@ -31,17 +34,22 @@ use bytes::Bytes; /// # Example /// ``` /// extern crate patricia_trie as trie; +/// extern crate patricia_trie_ethereum as ethtrie; /// extern crate hashdb; +/// extern crate keccak_hasher; /// extern crate memorydb; /// extern crate ethereum_types; /// /// use trie::*; /// use hashdb::*; +/// use keccak_hasher::KeccakHasher; /// use memorydb::*; /// use ethereum_types::H256; +/// use ethtrie::{TrieDB, TrieDBMut}; +/// /// /// fn main() { -/// let mut memdb = MemoryDB::new(); +/// let mut memdb = MemoryDB::::new(); /// let mut root = H256::new(); /// TrieDBMut::new(&mut memdb, &mut root).insert(b"foo", b"bar").unwrap(); /// let t = TrieDB::new(&memdb, &root).unwrap(); @@ -49,35 +57,38 @@ use bytes::Bytes; /// assert_eq!(t.get(b"foo").unwrap().unwrap(), DBValue::from_slice(b"bar")); /// } /// ``` -pub struct TrieDB<'db> { - db: &'db HashDB, - root: &'db H256, +pub struct TrieDB<'db, H, C> +where + H: Hasher + 'db, + C: NodeCodec +{ + db: &'db HashDB, + root: &'db H::Out, /// The number of hashes performed so far in operations on this trie. hash_count: usize, + codec_marker: PhantomData, } -impl<'db> TrieDB<'db> { +impl<'db, H, C> TrieDB<'db, H, C> +where + H: Hasher, + C: NodeCodec +{ /// Create a new trie with the backing database `db` and `root` /// Returns an error if `root` does not exist - pub fn new(db: &'db HashDB, root: &'db H256) -> super::Result { + pub fn new(db: &'db HashDB, root: &'db H::Out) -> Result { if !db.contains(root) { Err(Box::new(TrieError::InvalidStateRoot(*root))) } else { - Ok(TrieDB { - db: db, - root: root, - hash_count: 0 - }) + Ok(TrieDB {db, root, hash_count: 0, codec_marker: PhantomData}) } } /// Get the backing database. - pub fn db(&'db self) -> &'db HashDB { - self.db - } + pub fn db(&'db self) -> &'db HashDB { self.db } /// Get the data of the root node. - fn root_data(&self) -> super::Result { + fn root_data(&self) -> Result { self.db .get(self.root) .ok_or_else(|| Box::new(TrieError::InvalidStateRoot(*self.root))) @@ -86,49 +97,57 @@ impl<'db> TrieDB<'db> { /// Given some node-describing data `node`, return the actual node RLP. /// This could be a simple identity operation in the case that the node is sufficiently small, but /// may require a database lookup. - fn get_raw_or_lookup(&'db self, node: &'db [u8]) -> super::Result { - match Node::try_decode_hash(node) { + fn get_raw_or_lookup(&'db self, node: &'db [u8]) -> Result { + match C::try_decode_hash(node) { Some(key) => { self.db.get(&key).ok_or_else(|| Box::new(TrieError::IncompleteDatabase(key))) } None => Ok(DBValue::from_slice(node)) } } - - /// Create a node from raw rlp bytes, assumes valid rlp because encoded locally - fn decode_node(node: &'db [u8]) -> Node { - Node::decoded(node).expect("rlp read from db; qed") - } } -impl<'db> Trie for TrieDB<'db> { - fn iter<'a>(&'a self) -> super::Result + 'a>> { - TrieDBIterator::new(self).map(|iter| Box::new(iter) as Box<_>) - } - - fn root(&self) -> &H256 { self.root } +impl<'db, H, C> Trie for TrieDB<'db, H, C> +where + H: Hasher, + C: NodeCodec +{ + fn root(&self) -> &H::Out { self.root } - fn get_with<'a, 'key, Q: Query>(&'a self, key: &'key [u8], query: Q) -> super::Result> + fn get_with<'a, 'key, Q: Query>(&'a self, key: &'key [u8], query: Q) -> Result, H::Out, C::Error> where 'a: 'key { Lookup { db: self.db, query: query, hash: self.root.clone(), + marker: PhantomData::, }.look_up(NibbleSlice::new(key)) } + + fn iter<'a>(&'a self) -> Result> + 'a>, H::Out, C::Error> { + TrieDBIterator::new(self).map(|iter| Box::new(iter) as Box<_>) + } } // This is for pretty debug output only -struct TrieAwareDebugNode<'db, 'a> { - trie: &'db TrieDB<'db>, +struct TrieAwareDebugNode<'db, 'a, H, C> +where + H: Hasher + 'db, + C: NodeCodec + 'db +{ + trie: &'db TrieDB<'db, H, C>, key: &'a[u8] } -impl<'db, 'a> fmt::Debug for TrieAwareDebugNode<'db, 'a> { +impl<'db, 'a, H, C> fmt::Debug for TrieAwareDebugNode<'db, 'a, H, C> +where + H: Hasher, + C: NodeCodec +{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if let Ok(node) = self.trie.get_raw_or_lookup(self.key) { - match Node::decoded(&node) { + match C::decode(&node) { Ok(Node::Leaf(slice, value)) => f.debug_struct("Node::Leaf") .field("slice", &slice) .field("value", &value) @@ -138,7 +157,7 @@ impl<'db, 'a> fmt::Debug for TrieAwareDebugNode<'db, 'a> { .field("item", &TrieAwareDebugNode{trie: self.trie, key: item}) .finish(), Ok(Node::Branch(ref nodes, ref value)) => { - let nodes: Vec = nodes.into_iter().map(|n| TrieAwareDebugNode{trie: self.trie, key: n} ).collect(); + let nodes: Vec> = nodes.into_iter().map(|n| TrieAwareDebugNode{trie: self.trie, key: n} ).collect(); f.debug_struct("Node::Branch") .field("nodes", &nodes) .field("value", &value) @@ -160,8 +179,11 @@ impl<'db, 'a> fmt::Debug for TrieAwareDebugNode<'db, 'a> { } } - -impl<'db> fmt::Debug for TrieDB<'db> { +impl<'db, H, C> fmt::Debug for TrieDB<'db, H, C> +where + H: Hasher, + C: NodeCodec +{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let root_rlp = self.db.get(self.root).expect("Trie root not found!"); f.debug_struct("TrieDB") @@ -202,29 +224,24 @@ impl Crumb { } /// Iterator for going through all values in the trie. -pub struct TrieDBIterator<'a> { - db: &'a TrieDB<'a>, +pub struct TrieDBIterator<'a, H: Hasher + 'a, C: NodeCodec + 'a> { + db: &'a TrieDB<'a, H, C>, trail: Vec, key_nibbles: Bytes, } -impl<'a> TrieDBIterator<'a> { +impl<'a, H: Hasher, C: NodeCodec> TrieDBIterator<'a, H, C> { /// Create a new iterator. - pub fn new(db: &'a TrieDB) -> super::Result> { - let mut r = TrieDBIterator { - db: db, - trail: vec![], - key_nibbles: Vec::new(), - }; - + pub fn new(db: &'a TrieDB) -> Result, H::Out, C::Error> { + let mut r = TrieDBIterator { db, trail: Vec::with_capacity(8), key_nibbles: Vec::with_capacity(64) }; db.root_data().and_then(|root| r.descend(&root))?; Ok(r) } - fn seek<'key>(&mut self, mut node_data: DBValue, mut key: NibbleSlice<'key>) -> super::Result<()> { + fn seek<'key>(&mut self, mut node_data: DBValue, mut key: NibbleSlice<'key>) -> Result<(), H::Out, C::Error> { loop { let (data, mid) = { - let node = TrieDB::decode_node(&node_data); + let node = C::decode(&node_data).expect("encoded data read from db; qed"); match node { Node::Leaf(slice, _) => { if slice == key { @@ -285,17 +302,15 @@ impl<'a> TrieDBIterator<'a> { } /// Descend into a payload. - fn descend(&mut self, d: &[u8]) -> super::Result<()> { - let node = TrieDB::decode_node(&self.db.get_raw_or_lookup(d)?).into(); - Ok(self.descend_into_node(node)) + fn descend(&mut self, d: &[u8]) -> Result<(), H::Out, C::Error> { + let node_data = &self.db.get_raw_or_lookup(d)?; + let node = C::decode(&node_data).expect("encoded node read from db; qed"); + Ok(self.descend_into_node(node.into())) } /// Descend into a payload. fn descend_into_node(&mut self, node: OwnedNode) { - self.trail.push(Crumb { - status: Status::Entering, - node: node, - }); + self.trail.push(Crumb { status: Status::Entering, node }); match &self.trail.last().expect("just pushed item; qed").node { &OwnedNode::Leaf(ref n, _) | &OwnedNode::Extension(ref n, _) => { self.key_nibbles.extend((0..n.len()).map(|i| n.at(i))); @@ -319,26 +334,25 @@ impl<'a> TrieDBIterator<'a> { } } -impl<'a> TrieIterator for TrieDBIterator<'a> { +impl<'a, H: Hasher, C: NodeCodec> TrieIterator for TrieDBIterator<'a, H, C> { /// Position the iterator on the first element with key >= `key` - fn seek(&mut self, key: &[u8]) -> super::Result<()> { + fn seek(&mut self, key: &[u8]) -> Result<(), H::Out, C::Error> { self.trail.clear(); self.key_nibbles.clear(); let root_rlp = self.db.root_data()?; - self.seek(root_rlp, NibbleSlice::new(key)) + self.seek(root_rlp, NibbleSlice::new(key.as_ref())) } } -impl<'a> Iterator for TrieDBIterator<'a> { - type Item = TrieItem<'a>; +impl<'a, H: Hasher, C: NodeCodec> Iterator for TrieDBIterator<'a, H, C> { + type Item = TrieItem<'a, H::Out, C::Error>; fn next(&mut self) -> Option { - enum IterStep { + enum IterStep { Continue, PopTrail, - Descend(super::Result), + Descend(Result), } - loop { let iter_step = { self.trail.last_mut()?.increment(); @@ -359,7 +373,9 @@ impl<'a> Iterator for TrieDBIterator<'a> { (Status::At, &OwnedNode::Leaf(_, ref v)) | (Status::At, &OwnedNode::Branch(_, Some(ref v))) => { return Some(Ok((self.key(), v.clone()))); }, - (Status::At, &OwnedNode::Extension(_, ref d)) => IterStep::Descend(self.db.get_raw_or_lookup(&*d)), + (Status::At, &OwnedNode::Extension(_, ref d)) => { + IterStep::Descend::(self.db.get_raw_or_lookup(&*d)) + }, (Status::At, &OwnedNode::Branch(_, _)) => IterStep::Continue, (Status::AtChild(i), &OwnedNode::Branch(ref children, _)) if children[i].len() > 0 => { match i { @@ -367,7 +383,7 @@ impl<'a> Iterator for TrieDBIterator<'a> { i => *self.key_nibbles.last_mut() .expect("pushed as 0; moves sequentially; removed afterwards; qed") = i as u8, } - IterStep::Descend(self.db.get_raw_or_lookup(&*children[i])) + IterStep::Descend::(self.db.get_raw_or_lookup(&*children[i])) }, (Status::AtChild(i), &OwnedNode::Branch(_, _)) => { if i == 0 { @@ -383,10 +399,11 @@ impl<'a> Iterator for TrieDBIterator<'a> { IterStep::PopTrail => { self.trail.pop(); }, - IterStep::Descend(Ok(d)) => { - self.descend_into_node(TrieDB::decode_node(&d).into()) + IterStep::Descend::(Ok(d)) => { + let node = C::decode(&d).expect("encoded data read from db; qed"); + self.descend_into_node(node.into()) }, - IterStep::Descend(Err(e)) => { + IterStep::Descend::(Err(e)) => { return Some(Err(e)) } IterStep::Continue => {}, @@ -395,115 +412,106 @@ impl<'a> Iterator for TrieDBIterator<'a> { } } -#[test] -fn iterator() { - use memorydb::*; - use super::TrieMut; - use super::triedbmut::*; - - let d = vec![ DBValue::from_slice(b"A"), DBValue::from_slice(b"AA"), DBValue::from_slice(b"AB"), DBValue::from_slice(b"B") ]; - - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - { - let mut t = TrieDBMut::new(&mut memdb, &mut root); - for x in &d { - t.insert(x, x).unwrap(); +#[cfg(test)] +mod tests { + use hashdb::DBValue; + use keccak_hasher::KeccakHasher; + use memorydb::MemoryDB; + use ethtrie::{TrieDB, TrieDBMut, RlpCodec, trie::{Trie, TrieMut, Lookup}}; + use ethereum_types::H256; + + #[test] + fn iterator() { + let d = vec![DBValue::from_slice(b"A"), DBValue::from_slice(b"AA"), DBValue::from_slice(b"AB"), DBValue::from_slice(b"B")]; + + let mut memdb = MemoryDB::::new(); + let mut root = H256::new(); + { + let mut t = TrieDBMut::new(&mut memdb, &mut root); + for x in &d { + t.insert(x, x).unwrap(); + } } - } - - let t = TrieDB::new(&memdb, &root).unwrap(); - assert_eq!(d.iter().map(|i| i.clone().into_vec()).collect::>(), t.iter().unwrap().map(|x| x.unwrap().0).collect::>()); - assert_eq!(d, t.iter().unwrap().map(|x| x.unwrap().1).collect::>()); -} -#[test] -fn iterator_seek() { - use memorydb::*; - use super::TrieMut; - use super::triedbmut::*; - - let d = vec![ DBValue::from_slice(b"A"), DBValue::from_slice(b"AA"), DBValue::from_slice(b"AB"), DBValue::from_slice(b"B") ]; + let t = TrieDB::new(&memdb, &root).unwrap(); + assert_eq!(d.iter().map(|i| i.clone().into_vec()).collect::>(), t.iter().unwrap().map(|x| x.unwrap().0).collect::>()); + assert_eq!(d, t.iter().unwrap().map(|x| x.unwrap().1).collect::>()); + } - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - { - let mut t = TrieDBMut::new(&mut memdb, &mut root); - for x in &d { - t.insert(x, x).unwrap(); + #[test] + fn iterator_seek() { + let d = vec![ DBValue::from_slice(b"A"), DBValue::from_slice(b"AA"), DBValue::from_slice(b"AB"), DBValue::from_slice(b"B") ]; + + let mut memdb = MemoryDB::::new(); + let mut root = H256::new(); + { + let mut t = TrieDBMut::new(&mut memdb, &mut root); + for x in &d { + t.insert(x, x).unwrap(); + } } + + let t = TrieDB::new(&memdb, &root).unwrap(); + let mut iter = t.iter().unwrap(); + assert_eq!(iter.next().unwrap().unwrap(), (b"A".to_vec(), DBValue::from_slice(b"A"))); + iter.seek(b"!").unwrap(); + assert_eq!(d, iter.map(|x| x.unwrap().1).collect::>()); + let mut iter = t.iter().unwrap(); + iter.seek(b"A").unwrap(); + assert_eq!(&d[1..], &iter.map(|x| x.unwrap().1).collect::>()[..]); + let mut iter = t.iter().unwrap(); + iter.seek(b"AA").unwrap(); + assert_eq!(&d[2..], &iter.map(|x| x.unwrap().1).collect::>()[..]); + let mut iter = t.iter().unwrap(); + iter.seek(b"A!").unwrap(); + assert_eq!(&d[1..], &iter.map(|x| x.unwrap().1).collect::>()[..]); + let mut iter = t.iter().unwrap(); + iter.seek(b"AB").unwrap(); + assert_eq!(&d[3..], &iter.map(|x| x.unwrap().1).collect::>()[..]); + let mut iter = t.iter().unwrap(); + iter.seek(b"AB!").unwrap(); + assert_eq!(&d[3..], &iter.map(|x| x.unwrap().1).collect::>()[..]); + let mut iter = t.iter().unwrap(); + iter.seek(b"B").unwrap(); + assert_eq!(&d[4..], &iter.map(|x| x.unwrap().1).collect::>()[..]); + let mut iter = t.iter().unwrap(); + iter.seek(b"C").unwrap(); + assert_eq!(&d[4..], &iter.map(|x| x.unwrap().1).collect::>()[..]); } - let t = TrieDB::new(&memdb, &root).unwrap(); - let mut iter = t.iter().unwrap(); - assert_eq!(iter.next(), Some(Ok((b"A".to_vec(), DBValue::from_slice(b"A"))))); - iter.seek(b"!").unwrap(); - assert_eq!(d, iter.map(|x| x.unwrap().1).collect::>()); - let mut iter = t.iter().unwrap(); - iter.seek(b"A").unwrap(); - assert_eq!(&d[1..], &iter.map(|x| x.unwrap().1).collect::>()[..]); - let mut iter = t.iter().unwrap(); - iter.seek(b"AA").unwrap(); - assert_eq!(&d[2..], &iter.map(|x| x.unwrap().1).collect::>()[..]); - let mut iter = t.iter().unwrap(); - iter.seek(b"A!").unwrap(); - assert_eq!(&d[1..], &iter.map(|x| x.unwrap().1).collect::>()[..]); - let mut iter = t.iter().unwrap(); - iter.seek(b"AB").unwrap(); - assert_eq!(&d[3..], &iter.map(|x| x.unwrap().1).collect::>()[..]); - let mut iter = t.iter().unwrap(); - iter.seek(b"AB!").unwrap(); - assert_eq!(&d[3..], &iter.map(|x| x.unwrap().1).collect::>()[..]); - let mut iter = t.iter().unwrap(); - iter.seek(b"B").unwrap(); - assert_eq!(&d[4..], &iter.map(|x| x.unwrap().1).collect::>()[..]); - let mut iter = t.iter().unwrap(); - iter.seek(b"C").unwrap(); - assert_eq!(&d[4..], &iter.map(|x| x.unwrap().1).collect::>()[..]); -} - -#[test] -fn get_len() { - use memorydb::*; - use super::TrieMut; - use super::triedbmut::*; + #[test] + fn get_len() { + let mut memdb = MemoryDB::::new(); + let mut root = H256::new(); + { + let mut t = TrieDBMut::new(&mut memdb, &mut root); + t.insert(b"A", b"ABC").unwrap(); + t.insert(b"B", b"ABCBA").unwrap(); + } - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - { - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(b"A", b"ABC").unwrap(); - t.insert(b"B", b"ABCBA").unwrap(); + let t = TrieDB::new(&memdb, &root).unwrap(); + assert_eq!(t.get_with(b"A", |x: &[u8]| x.len()).unwrap(), Some(3)); + assert_eq!(t.get_with(b"B", |x: &[u8]| x.len()).unwrap(), Some(5)); + assert_eq!(t.get_with(b"C", |x: &[u8]| x.len()).unwrap(), None); } - let t = TrieDB::new(&memdb, &root).unwrap(); - assert_eq!(t.get_with(b"A", |x: &[u8]| x.len()), Ok(Some(3))); - assert_eq!(t.get_with(b"B", |x: &[u8]| x.len()), Ok(Some(5))); - assert_eq!(t.get_with(b"C", |x: &[u8]| x.len()), Ok(None)); -} - - -#[test] -fn debug_output_supports_pretty_print() { - use memorydb::*; - use super::TrieMut; - use super::triedbmut::*; - - let d = vec![ DBValue::from_slice(b"A"), DBValue::from_slice(b"AA"), DBValue::from_slice(b"AB"), DBValue::from_slice(b"B") ]; + #[test] + fn debug_output_supports_pretty_print() { + let d = vec![ DBValue::from_slice(b"A"), DBValue::from_slice(b"AA"), DBValue::from_slice(b"AB"), DBValue::from_slice(b"B") ]; - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - let root = { - let mut t = TrieDBMut::new(&mut memdb, &mut root); - for x in &d { - t.insert(x, x).unwrap(); - } - t.root().clone() - }; - let t = TrieDB::new(&memdb, &root).unwrap(); + let mut memdb = MemoryDB::::new(); + let mut root = H256::new(); + let root = { + let mut t = TrieDBMut::new(&mut memdb, &mut root); + for x in &d { + t.insert(x, x).unwrap(); + } + t.root().clone() + }; + let t = TrieDB::new(&memdb, &root).unwrap(); - assert_eq!(format!("{:?}", t), "TrieDB { hash_count: 0, root: Node::Extension { slice: 4, item: Node::Branch { nodes: [Node::Empty, Node::Branch { nodes: [Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Branch { nodes: [Node::Empty, Node::Leaf { slice: , value: [65, 65] }, Node::Leaf { slice: , value: [65, 66] }, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty], value: None }, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty], value: Some([65]) }, Node::Leaf { slice: , value: [66] }, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty], value: None } } }"); - assert_eq!(format!("{:#?}", t), + assert_eq!(format!("{:?}", t), "TrieDB { hash_count: 0, root: Node::Extension { slice: 4, item: Node::Branch { nodes: [Node::Empty, Node::Branch { nodes: [Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Branch { nodes: [Node::Empty, Node::Leaf { slice: , value: [65, 65] }, Node::Leaf { slice: , value: [65, 66] }, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty], value: None }, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty], value: Some([65]) }, Node::Leaf { slice: , value: [66] }, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty], value: None } } }"); + assert_eq!(format!("{:#?}", t), "TrieDB { hash_count: 0, root: Node::Extension { @@ -592,29 +600,29 @@ fn debug_output_supports_pretty_print() { } } }"); -} - -#[test] -fn test_lookup_with_corrupt_data_returns_decoder_error() { - use memorydb::*; - use super::TrieMut; - use super::triedbmut::*; - use rlp; - use ethereum_types::H512; - - let mut memdb = MemoryDB::new(); - let mut root = H256::new(); - { - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(b"A", b"ABC").unwrap(); - t.insert(b"B", b"ABCBA").unwrap(); } - let t = TrieDB::new(&memdb, &root).unwrap(); + #[test] + fn test_lookup_with_corrupt_data_returns_decoder_error() { + use rlp; + use ethereum_types::H512; + use std::marker::PhantomData; + use ethtrie::trie::NibbleSlice; + + let mut memdb = MemoryDB::::new(); + let mut root = H256::new(); + { + let mut t = TrieDBMut::new(&mut memdb, &mut root); + t.insert(b"A", b"ABC").unwrap(); + t.insert(b"B", b"ABCBA").unwrap(); + } - // query for an invalid data type to trigger an error - let q = rlp::decode::; - let lookup = Lookup{ db: t.db, query: q, hash: root }; - let query_result = lookup.look_up(NibbleSlice::new(b"A")); - assert_eq!(query_result.unwrap().unwrap().unwrap_err(), rlp::DecoderError::RlpIsTooShort); -} + let t = TrieDB::new(&memdb, &root).unwrap(); + + // query for an invalid data type to trigger an error + let q = rlp::decode::; + let lookup = Lookup::<_, RlpCodec, _>{ db: t.db(), query: q, hash: root, marker: PhantomData }; + let query_result = lookup.look_up(NibbleSlice::new(b"A")); + assert_eq!(query_result.unwrap().unwrap().unwrap_err(), rlp::DecoderError::RlpIsTooShort); + } +} \ No newline at end of file diff --git a/util/patricia_trie/src/triedbmut.rs b/util/patricia_trie/src/triedbmut.rs index 994045eb3a7..4490285d51d 100644 --- a/util/patricia_trie/src/triedbmut.rs +++ b/util/patricia_trie/src/triedbmut.rs @@ -16,23 +16,23 @@ //! In-memory trie representation. -use super::{TrieError, TrieMut}; +use super::{Result, TrieError, TrieMut}; use super::lookup::Lookup; -use super::node::Node as RlpNode; +use super::node::Node as EncodedNode; +use node_codec::NodeCodec; use super::node::NodeKey; -use hashdb::HashDB; use bytes::ToPretty; +use hashdb::{HashDB, Hasher, DBValue}; use nibbleslice::NibbleSlice; -use rlp::{Rlp, RlpStream}; -use hashdb::DBValue; +use elastic_array::ElasticArray1024; use std::collections::{HashSet, VecDeque}; +use std::marker::PhantomData; use std::mem; use std::ops::Index; -use ethereum_types::H256; -use elastic_array::ElasticArray1024; -use keccak::{KECCAK_NULL_RLP}; +use heapsize::HeapSizeOf; +use std::{fmt::Debug, hash::Hash}; // For lookups into the Node storage buffer. // This is deliberately non-copyable. @@ -41,26 +41,20 @@ struct StorageHandle(usize); // Handles to nodes in the trie. #[derive(Debug)] -enum NodeHandle { +enum NodeHandle { /// Loaded into memory. InMemory(StorageHandle), /// Either a hash or an inline node - Hash(H256), + Hash(H), } -impl From for NodeHandle { +impl From for NodeHandle { fn from(handle: StorageHandle) -> Self { NodeHandle::InMemory(handle) } } -impl From for NodeHandle { - fn from(hash: H256) -> Self { - NodeHandle::Hash(hash) - } -} - -fn empty_children() -> Box<[Option; 16]> { +fn empty_children() -> Box<[Option>; 16]> { Box::new([ None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, @@ -69,7 +63,7 @@ fn empty_children() -> Box<[Option; 16]> { /// Node types in the Trie. #[derive(Debug)] -enum Node { +enum Node { /// Empty node. Empty, /// A leaf node contains the end of a key and a value. @@ -80,36 +74,43 @@ enum Node { /// The shared portion is encoded from a `NibbleSlice` meaning it contains /// a flag indicating it is an extension. /// The child node is always a branch. - Extension(NodeKey, NodeHandle), + Extension(NodeKey, NodeHandle), /// A branch has up to 16 children and an optional value. - Branch(Box<[Option; 16]>, Option) + Branch(Box<[Option>; 16]>, Option) } -impl Node { +impl Node where O: AsRef<[u8]> + AsMut<[u8]> + Default + HeapSizeOf + Debug + PartialEq + Eq + Hash + Send + Sync + Clone + Copy { // load an inline node into memory or get the hash to do the lookup later. - fn inline_or_hash(node: &[u8], db: &HashDB, storage: &mut NodeStorage) -> NodeHandle { - RlpNode::try_decode_hash(&node) + fn inline_or_hash(node: &[u8], db: &HashDB, storage: &mut NodeStorage) -> NodeHandle + where C: NodeCodec, + H: Hasher, + { + C::try_decode_hash(&node) .map(NodeHandle::Hash) .unwrap_or_else(|| { - let child = Node::from_rlp(node, db, storage); + let child = Node::from_encoded::(node, db, storage); NodeHandle::InMemory(storage.alloc(Stored::New(child))) }) } - // decode a node from rlp without getting its children. - fn from_rlp(rlp: &[u8], db: &HashDB, storage: &mut NodeStorage) -> Self { - match RlpNode::decoded(rlp).expect("rlp read from db; qed") { - RlpNode::Empty => Node::Empty, - RlpNode::Leaf(k, v) => Node::Leaf(k.encoded(true), DBValue::from_slice(&v)), - RlpNode::Extension(key, cb) => { - Node::Extension(key.encoded(false), Self::inline_or_hash(cb, db, storage)) + // decode a node from encoded bytes without getting its children. + fn from_encoded(data: &[u8], db: &HashDB, storage: &mut NodeStorage) -> Self + where C: NodeCodec, + H: Hasher, + { + match C::decode(data).expect("encoded bytes read from db; qed") { + EncodedNode::Empty => Node::Empty, + EncodedNode::Leaf(k, v) => Node::Leaf(k.encoded(true), DBValue::from_slice(&v)), + EncodedNode::Extension(key, cb) => { + Node::Extension( + key.encoded(false), + Self::inline_or_hash::(cb, db, storage)) } - RlpNode::Branch(ref children_rlp, val) => { - let mut child = |i| { - let raw = children_rlp[i]; - let child_rlp = Rlp::new(raw); - if !child_rlp.is_empty() { - Some(Self::inline_or_hash(raw, db, storage)) + EncodedNode::Branch(ref encoded_children, val) => { + let mut child = |i:usize| { + let raw = encoded_children[i]; + if !C::is_empty_node(raw) { + Some(Self::inline_or_hash::(raw, db, storage)) } else { None } @@ -127,70 +128,52 @@ impl Node { } } - // encode a node to RLP // TODO: parallelize - fn into_rlp(self, mut child_cb: F) -> ElasticArray1024 - where F: FnMut(NodeHandle, &mut RlpStream) + fn into_encoded(self, mut child_cb: F) -> ElasticArray1024 + where + C: NodeCodec, + F: FnMut(NodeHandle) -> ChildReference, + H: Hasher, { match self { - Node::Empty => { - let mut stream = RlpStream::new(); - stream.append_empty_data(); - stream.drain() - } - Node::Leaf(partial, value) => { - let mut stream = RlpStream::new_list(2); - stream.append(&&*partial); - stream.append(&&*value); - stream.drain() - } - Node::Extension(partial, child) => { - let mut stream = RlpStream::new_list(2); - stream.append(&&*partial); - child_cb(child, &mut stream); - stream.drain() - } + Node::Empty => C::empty_node(), + Node::Leaf(partial, value) => C::leaf_node(&partial, &value), + Node::Extension(partial, child) => C::ext_node(&partial, child_cb(child)), Node::Branch(mut children, value) => { - let mut stream = RlpStream::new_list(17); - for child in children.iter_mut().map(Option::take) { - if let Some(handle) = child { - child_cb(handle, &mut stream); - } else { - stream.append_empty_data(); - } - } - if let Some(value) = value { - stream.append(&&*value); - } else { - stream.append_empty_data(); - } - - stream.drain() + C::branch_node( + // map the `NodeHandle`s from the Branch to `ChildReferences` + children.iter_mut() + .map(Option::take) + .map(|maybe_child| + maybe_child.map(|child| child_cb(child)) + ), + value + ) } } } } // post-inspect action. -enum Action { +enum Action { // Replace a node with a new one. - Replace(Node), + Replace(Node), // Restore the original node. This trusts that the node is actually the original. - Restore(Node), + Restore(Node), // if it is a new node, just clears the storage. Delete, } // post-insert action. Same as action without delete -enum InsertAction { +enum InsertAction { // Replace a node with a new one. - Replace(Node), + Replace(Node), // Restore the original node. - Restore(Node), + Restore(Node), } -impl InsertAction { - fn into_action(self) -> Action { +impl InsertAction { + fn into_action(self) -> Action { match self { InsertAction::Replace(n) => Action::Replace(n), InsertAction::Restore(n) => Action::Restore(n), @@ -198,7 +181,7 @@ impl InsertAction { } // unwrap the node, disregarding replace or restore state. - fn unwrap_node(self) -> Node { + fn unwrap_node(self) -> Node { match self { InsertAction::Replace(n) | InsertAction::Restore(n) => n, } @@ -206,20 +189,26 @@ impl InsertAction { } // What kind of node is stored here. -enum Stored { +enum Stored { // A new node. - New(Node), + New(Node), // A cached node, loaded from the DB. - Cached(Node, H256), + Cached(Node, H), +} + +/// Used to build a collection of child nodes from a collection of `NodeHandle`s +pub enum ChildReference { // `HO` is e.g. `H256`, i.e. the output of a `Hasher` + Hash(HO), + Inline(HO, usize), // usize is the length of the node data we store in the `H::Out` } /// Compact and cache-friendly storage for Trie nodes. -struct NodeStorage { - nodes: Vec, +struct NodeStorage { + nodes: Vec>, free_indices: VecDeque, } -impl NodeStorage { +impl NodeStorage { /// Create a new storage. fn empty() -> Self { NodeStorage { @@ -229,7 +218,7 @@ impl NodeStorage { } /// Allocate a new node in the storage. - fn alloc(&mut self, stored: Stored) -> StorageHandle { + fn alloc(&mut self, stored: Stored) -> StorageHandle { if let Some(idx) = self.free_indices.pop_front() { self.nodes[idx] = stored; StorageHandle(idx) @@ -240,7 +229,7 @@ impl NodeStorage { } /// Remove a node from the storage, consuming the handle and returning the node. - fn destroy(&mut self, handle: StorageHandle) -> Stored { + fn destroy(&mut self, handle: StorageHandle) -> Stored { let idx = handle.0; self.free_indices.push_back(idx); @@ -248,10 +237,10 @@ impl NodeStorage { } } -impl<'a> Index<&'a StorageHandle> for NodeStorage { - type Output = Node; +impl<'a, H> Index<&'a StorageHandle> for NodeStorage { + type Output = Node; - fn index(&self, handle: &'a StorageHandle) -> &Node { + fn index(&self, handle: &'a StorageHandle) -> &Node { match self.nodes[handle.0] { Stored::New(ref node) => node, Stored::Cached(ref node, _) => node, @@ -268,19 +257,22 @@ impl<'a> Index<&'a StorageHandle> for NodeStorage { /// # Example /// ``` /// extern crate patricia_trie as trie; -/// extern crate keccak_hash; +/// extern crate patricia_trie_ethereum as ethtrie; /// extern crate hashdb; +/// extern crate keccak_hash; +/// extern crate keccak_hasher; /// extern crate memorydb; /// extern crate ethereum_types; /// /// use keccak_hash::KECCAK_NULL_RLP; -/// use trie::*; -/// use hashdb::*; +/// use ethtrie::{TrieDBMut, trie::TrieMut}; +/// use hashdb::DBValue; +/// use keccak_hasher::KeccakHasher; /// use memorydb::*; /// use ethereum_types::H256; /// /// fn main() { -/// let mut memdb = MemoryDB::new(); +/// let mut memdb = MemoryDB::::new(); /// let mut root = H256::new(); /// let mut t = TrieDBMut::new(&mut memdb, &mut root); /// assert!(t.is_empty()); @@ -292,22 +284,31 @@ impl<'a> Index<&'a StorageHandle> for NodeStorage { /// assert!(!t.contains(b"foo").unwrap()); /// } /// ``` -pub struct TrieDBMut<'a> { - storage: NodeStorage, - db: &'a mut HashDB, - root: &'a mut H256, - root_handle: NodeHandle, - death_row: HashSet, +pub struct TrieDBMut<'a, H, C> +where + H: Hasher + 'a, + C: NodeCodec +{ + storage: NodeStorage, + db: &'a mut HashDB, + root: &'a mut H::Out, + root_handle: NodeHandle, + death_row: HashSet, /// The number of hash operations this trie has performed. /// Note that none are performed until changes are committed. hash_count: usize, + marker: PhantomData, // TODO: rpheimer: "we could have the NodeCodec trait take &self to its methods and then we don't need PhantomData. we can just store an instance of C: NodeCodec in the trie struct. If it's a ZST it won't have any additional overhead anyway" } -impl<'a> TrieDBMut<'a> { +impl<'a, H, C> TrieDBMut<'a, H, C> +where + H: Hasher, + C: NodeCodec +{ /// Create a new trie with backing database `db` and empty `root`. - pub fn new(db: &'a mut HashDB, root: &'a mut H256) -> Self { - *root = KECCAK_NULL_RLP; - let root_handle = NodeHandle::Hash(KECCAK_NULL_RLP); + pub fn new(db: &'a mut HashDB, root: &'a mut H::Out) -> Self { + *root = C::HASHED_NULL_NODE; + let root_handle = NodeHandle::Hash(C::HASHED_NULL_NODE); TrieDBMut { storage: NodeStorage::empty(), @@ -316,12 +317,13 @@ impl<'a> TrieDBMut<'a> { root_handle: root_handle, death_row: HashSet::new(), hash_count: 0, + marker: PhantomData, } } /// Create a new trie with the backing database `db` and `root. /// Returns an error if `root` does not exist. - pub fn from_existing(db: &'a mut HashDB, root: &'a mut H256) -> super::Result { + pub fn from_existing(db: &'a mut HashDB, root: &'a mut H::Out) -> Result { if !db.contains(root) { return Err(Box::new(TrieError::InvalidStateRoot(*root))); } @@ -334,29 +336,34 @@ impl<'a> TrieDBMut<'a> { root_handle: root_handle, death_row: HashSet::new(), hash_count: 0, + marker: PhantomData, }) } /// Get the backing database. - pub fn db(&self) -> &HashDB { + pub fn db(&self) -> &HashDB { self.db } /// Get the backing database mutably. - pub fn db_mut(&mut self) -> &mut HashDB { + pub fn db_mut(&mut self) -> &mut HashDB { self.db } // cache a node by hash - fn cache(&mut self, hash: H256) -> super::Result { - let node_rlp = self.db.get(&hash).ok_or_else(|| Box::new(TrieError::IncompleteDatabase(hash)))?; - let node = Node::from_rlp(&node_rlp, &*self.db, &mut self.storage); + fn cache(&mut self, hash: H::Out) -> Result { + let node_encoded = self.db.get(&hash).ok_or_else(|| Box::new(TrieError::IncompleteDatabase(hash)))?; + let node = Node::from_encoded::( + &node_encoded, + &*self.db, + &mut self.storage + ); Ok(self.storage.alloc(Stored::Cached(node, hash))) } // inspect a node, choosing either to replace, restore, or delete it. // if restored or replaced, returns the new node along with a flag of whether it was changed. - fn inspect(&mut self, stored: Stored, inspector: F) -> super::Result> - where F: FnOnce(&mut Self, Node) -> super::Result { + fn inspect(&mut self, stored: Stored, inspector: F) -> Result, bool)>, H::Out, C::Error> + where F: FnOnce(&mut Self, Node) -> Result, H::Out, C::Error> { Ok(match stored { Stored::New(node) => match inspector(self, node)? { Action::Restore(node) => Some((Stored::New(node), false)), @@ -378,16 +385,17 @@ impl<'a> TrieDBMut<'a> { } // walk the trie, attempting to find the key's node. - fn lookup<'x, 'key>(&'x self, mut partial: NibbleSlice<'key>, handle: &NodeHandle) -> super::Result> + fn lookup<'x, 'key>(&'x self, mut partial: NibbleSlice<'key>, handle: &NodeHandle) -> Result, H::Out, C::Error> where 'x: 'key { let mut handle = handle; loop { let (mid, child) = match *handle { - NodeHandle::Hash(ref hash) => return Lookup { + NodeHandle::Hash(ref hash) => return Lookup{ db: &*self.db, query: DBValue::from_slice, hash: hash.clone(), + marker: PhantomData::, }.look_up(partial), NodeHandle::InMemory(ref handle) => match self.storage[handle] { Node::Empty => return Ok(None), @@ -425,10 +433,8 @@ impl<'a> TrieDBMut<'a> { } } - /// insert a key, value pair into the trie, creating new nodes if necessary. - fn insert_at(&mut self, handle: NodeHandle, partial: NibbleSlice, value: DBValue, old_val: &mut Option) - -> super::Result<(StorageHandle, bool)> - { + /// insert a key-value pair into the trie, creating new nodes if necessary. + fn insert_at(&mut self, handle: NodeHandle, partial: NibbleSlice, value: DBValue, old_val: &mut Option) -> Result<(StorageHandle, bool), H::Out, C::Error> { let h = match handle { NodeHandle::InMemory(h) => h, NodeHandle::Hash(h) => self.cache(h)?, @@ -442,9 +448,7 @@ impl<'a> TrieDBMut<'a> { } /// the insertion inspector. - fn insert_inspector(&mut self, node: Node, partial: NibbleSlice, value: DBValue, old_val: &mut Option) - -> super::Result - { + fn insert_inspector(&mut self, node: Node, partial: NibbleSlice, value: DBValue, old_val: &mut Option) -> Result, H::Out, C::Error> { trace!(target: "trie", "augmented (partial: {:?}, value: {:?})", partial, value.pretty()); Ok(match node { @@ -605,9 +609,7 @@ impl<'a> TrieDBMut<'a> { } /// Remove a node from the trie based on key. - fn remove_at(&mut self, handle: NodeHandle, partial: NibbleSlice, old_val: &mut Option) - -> super::Result> - { + fn remove_at(&mut self, handle: NodeHandle, partial: NibbleSlice, old_val: &mut Option) -> Result, H::Out, C::Error> { let stored = match handle { NodeHandle::InMemory(h) => self.storage.destroy(h), NodeHandle::Hash(h) => { @@ -622,7 +624,7 @@ impl<'a> TrieDBMut<'a> { } /// the removal inspector - fn remove_inspector(&mut self, node: Node, partial: NibbleSlice, old_val: &mut Option) -> super::Result { + fn remove_inspector(&mut self, node: Node, partial: NibbleSlice, old_val: &mut Option) -> Result, H::Out, C::Error> { Ok(match (node, partial.is_empty()) { (Node::Empty, _) => Action::Delete, (Node::Branch(c, None), true) => Action::Restore(Node::Branch(c, None)), @@ -708,7 +710,7 @@ impl<'a> TrieDBMut<'a> { /// _invalid state_ means: /// - Branch node where there is only a single entry; /// - Extension node followed by anything other than a Branch node. - fn fix(&mut self, node: Node) -> super::Result { + fn fix(&mut self, node: Node) -> Result, H::Out, C::Error> { match node { Node::Branch(mut children, value) => { // if only a single value, transmute to leaf/extension and feed through fixed. @@ -828,11 +830,11 @@ impl<'a> TrieDBMut<'a> { match self.storage.destroy(handle) { Stored::New(node) => { - let root_rlp = node.into_rlp(|child, stream| self.commit_node(child, stream)); - *self.root = self.db.insert(&root_rlp[..]); + let encoded_root = node.into_encoded::<_, C, H>(|child| self.commit_child(child) ); + *self.root = self.db.insert(&encoded_root[..]); self.hash_count += 1; - trace!(target: "trie", "root node rlp: {:?}", (&root_rlp[..]).pretty()); + trace!(target: "trie", "encoded root node: {:?}", (&encoded_root[..]).pretty()); self.root_handle = NodeHandle::Hash(*self.root); } Stored::Cached(node, hash) => { @@ -843,29 +845,38 @@ impl<'a> TrieDBMut<'a> { } } - /// commit a node, hashing it, committing it to the db, - /// and writing it to the rlp stream as necessary. - fn commit_node(&mut self, handle: NodeHandle, stream: &mut RlpStream) { + /// Commit a node by hashing it and writing it to the db. Returns a + /// `ChildReference` which in most cases carries a normal hash but for the + /// case where we can fit the actual data in the `Hasher`s output type, we + /// store the data inline. This function is used as the callback to the + /// `into_encoded` method of `Node`. + fn commit_child(&mut self, handle: NodeHandle) -> ChildReference { match handle { - NodeHandle::Hash(h) => stream.append(&h), - NodeHandle::InMemory(h) => match self.storage.destroy(h) { - Stored::Cached(_, h) => stream.append(&h), - Stored::New(node) => { - let node_rlp = node.into_rlp(|child, stream| self.commit_node(child, stream)); - if node_rlp.len() >= 32 { - let hash = self.db.insert(&node_rlp[..]); - self.hash_count += 1; - stream.append(&hash) - } else { - stream.append_raw(&node_rlp, 1) + NodeHandle::Hash(hash) => ChildReference::Hash(hash), + NodeHandle::InMemory(storage_handle) => { + match self.storage.destroy(storage_handle) { + Stored::Cached(_, hash) => ChildReference::Hash(hash), + Stored::New(node) => { + let encoded = node.into_encoded::<_, C, H>(|node_handle| self.commit_child(node_handle) ); + if encoded.len() >= H::LENGTH { + let hash = self.db.insert(&encoded[..]); + self.hash_count +=1; + ChildReference::Hash(hash) + } else { + // it's a small value, so we cram it into a `H::Out` and tag with length + let mut h = H::Out::default(); + let len = encoded.len(); + h.as_mut()[..len].copy_from_slice(&encoded[..len]); + ChildReference::Inline(h, len) + } } } } - }; + } } // a hack to get the root node's handle - fn root_handle(&self) -> NodeHandle { + fn root_handle(&self) -> NodeHandle { match self.root_handle { NodeHandle::Hash(h) => NodeHandle::Hash(h), NodeHandle::InMemory(StorageHandle(x)) => NodeHandle::InMemory(StorageHandle(x)), @@ -873,15 +884,19 @@ impl<'a> TrieDBMut<'a> { } } -impl<'a> TrieMut for TrieDBMut<'a> { - fn root(&mut self) -> &H256 { +impl<'a, H, C> TrieMut for TrieDBMut<'a, H, C> +where + H: Hasher, + C: NodeCodec +{ + fn root(&mut self) -> &H::Out { self.commit(); self.root } fn is_empty(&self) -> bool { match self.root_handle { - NodeHandle::Hash(h) => h == KECCAK_NULL_RLP, + NodeHandle::Hash(h) => h == C::HASHED_NULL_NODE, NodeHandle::InMemory(ref h) => match self.storage[h] { Node::Empty => true, _ => false, @@ -889,11 +904,13 @@ impl<'a> TrieMut for TrieDBMut<'a> { } } - fn get<'x, 'key>(&'x self, key: &'key [u8]) -> super::Result> where 'x: 'key { + fn get<'x, 'key>(&'x self, key: &'key [u8]) -> Result, H::Out, C::Error> + where 'x: 'key + { self.lookup(NibbleSlice::new(key), &self.root_handle) } - fn insert(&mut self, key: &[u8], value: &[u8]) -> super::Result> { + fn insert(&mut self, key: &[u8], value: &[u8]) -> Result, H::Out, C::Error> { if value.is_empty() { return self.remove(key) } let mut old_val = None; @@ -914,7 +931,7 @@ impl<'a> TrieMut for TrieDBMut<'a> { Ok(old_val) } - fn remove(&mut self, key: &[u8]) -> super::Result> { + fn remove(&mut self, key: &[u8]) -> Result, H::Out, C::Error> { trace!(target: "trie", "remove: key={:?}", key.pretty()); let root_handle = self.root_handle(); @@ -928,8 +945,8 @@ impl<'a> TrieMut for TrieDBMut<'a> { } None => { trace!(target: "trie", "remove: obliterated trie"); - self.root_handle = NodeHandle::Hash(KECCAK_NULL_RLP); - *self.root = KECCAK_NULL_RLP; + self.root_handle = NodeHandle::Hash(C::HASHED_NULL_NODE); + *self.root = C::HASHED_NULL_NODE; } } @@ -937,7 +954,11 @@ impl<'a> TrieMut for TrieDBMut<'a> { } } -impl<'a> Drop for TrieDBMut<'a> { +impl<'a, H, C> Drop for TrieDBMut<'a, H, C> +where + H: Hasher, + C: NodeCodec +{ fn drop(&mut self) { self.commit(); } @@ -945,18 +966,20 @@ impl<'a> Drop for TrieDBMut<'a> { #[cfg(test)] mod tests { - extern crate triehash; - - use self::triehash::trie_root; - use hashdb::*; - use memorydb::*; - use super::*; use bytes::ToPretty; - use keccak::KECCAK_NULL_RLP; - use super::super::TrieMut; + use hashdb::{DBValue, Hasher, HashDB}; + use keccak_hasher::KeccakHasher; + use memorydb::MemoryDB; + use rlp::{Decodable, Encodable}; + use triehash::trie_root; use standardmap::*; + use ethtrie::{TrieDBMut, RlpCodec, trie::{TrieMut, NodeCodec}}; + use env_logger; + use ethereum_types::H256; - fn populate_trie<'db>(db: &'db mut HashDB, root: &'db mut H256, v: &[(Vec, Vec)]) -> TrieDBMut<'db> { + fn populate_trie<'db, H, C>(db: &'db mut HashDB, root: &'db mut H256, v: &[(Vec, Vec)]) -> TrieDBMut<'db> + where H: Hasher, H::Out: Decodable + Encodable, C: NodeCodec + { let mut t = TrieDBMut::new(db, root); for i in 0..v.len() { let key: &[u8]= &v[i].0; @@ -975,8 +998,7 @@ mod tests { #[test] fn playpen() { - ::ethcore_logger::init_log(); - + env_logger::init(); let mut seed = H256::new(); for test_i in 0..10 { if test_i % 50 == 0 { @@ -991,9 +1013,9 @@ mod tests { }.make_with(&mut seed); let real = trie_root(x.clone()); - let mut memdb = MemoryDB::new(); + let mut memdb = MemoryDB::::new(); let mut root = H256::new(); - let mut memtrie = populate_trie(&mut memdb, &mut root, &x); + let mut memtrie = populate_trie::<_, RlpCodec>(&mut memdb, &mut root, &x); memtrie.commit(); if *memtrie.root() != real { @@ -1007,7 +1029,7 @@ mod tests { assert_eq!(*memtrie.root(), real); unpopulate_trie(&mut memtrie, &x); memtrie.commit(); - if *memtrie.root() != KECCAK_NULL_RLP { + if *memtrie.root() != RlpCodec::HASHED_NULL_NODE { println!("- TRIE MISMATCH"); println!(""); println!("{:?} vs {:?}", memtrie.root(), real); @@ -1015,21 +1037,21 @@ mod tests { println!("{:?} -> {:?}", i.0.pretty(), i.1.pretty()); } } - assert_eq!(*memtrie.root(), KECCAK_NULL_RLP); + assert_eq!(*memtrie.root(), RlpCodec::HASHED_NULL_NODE); } } #[test] fn init() { - let mut memdb = MemoryDB::new(); + let mut memdb = MemoryDB::::new(); let mut root = H256::new(); let mut t = TrieDBMut::new(&mut memdb, &mut root); - assert_eq!(*t.root(), KECCAK_NULL_RLP); + assert_eq!(*t.root(), RlpCodec::HASHED_NULL_NODE); } #[test] fn insert_on_empty() { - let mut memdb = MemoryDB::new(); + let mut memdb = MemoryDB::::new(); let mut root = H256::new(); let mut t = TrieDBMut::new(&mut memdb, &mut root); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); @@ -1040,14 +1062,15 @@ mod tests { fn remove_to_empty() { let big_value = b"00000000000000000000000000000000"; - let mut memdb = MemoryDB::new(); + let mut memdb = MemoryDB::::new(); let mut root = H256::new(); let mut t1 = TrieDBMut::new(&mut memdb, &mut root); t1.insert(&[0x01, 0x23], big_value).unwrap(); t1.insert(&[0x01, 0x34], big_value).unwrap(); - let mut memdb2 = MemoryDB::new(); + let mut memdb2 = MemoryDB::::new(); let mut root2 = H256::new(); let mut t2 = TrieDBMut::new(&mut memdb2, &mut root2); + t2.insert(&[0x01], big_value).unwrap(); t2.insert(&[0x01, 0x23], big_value).unwrap(); t2.insert(&[0x01, 0x34], big_value).unwrap(); @@ -1056,7 +1079,7 @@ mod tests { #[test] fn insert_replace_root() { - let mut memdb = MemoryDB::new(); + let mut memdb = MemoryDB::::new(); let mut root = H256::new(); let mut t = TrieDBMut::new(&mut memdb, &mut root); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); @@ -1066,7 +1089,7 @@ mod tests { #[test] fn insert_make_branch_root() { - let mut memdb = MemoryDB::new(); + let mut memdb = MemoryDB::::new(); let mut root = H256::new(); let mut t = TrieDBMut::new(&mut memdb, &mut root); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); @@ -1079,7 +1102,7 @@ mod tests { #[test] fn insert_into_branch_root() { - let mut memdb = MemoryDB::new(); + let mut memdb = MemoryDB::::new(); let mut root = H256::new(); let mut t = TrieDBMut::new(&mut memdb, &mut root); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); @@ -1094,7 +1117,7 @@ mod tests { #[test] fn insert_value_into_branch_root() { - let mut memdb = MemoryDB::new(); + let mut memdb = MemoryDB::::new(); let mut root = H256::new(); let mut t = TrieDBMut::new(&mut memdb, &mut root); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); @@ -1107,7 +1130,7 @@ mod tests { #[test] fn insert_split_leaf() { - let mut memdb = MemoryDB::new(); + let mut memdb = MemoryDB::::new(); let mut root = H256::new(); let mut t = TrieDBMut::new(&mut memdb, &mut root); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); @@ -1120,7 +1143,7 @@ mod tests { #[test] fn insert_split_extenstion() { - let mut memdb = MemoryDB::new(); + let mut memdb = MemoryDB::::new(); let mut root = H256::new(); let mut t = TrieDBMut::new(&mut memdb, &mut root); t.insert(&[0x01, 0x23, 0x45], &[0x01]).unwrap(); @@ -1138,7 +1161,7 @@ mod tests { let big_value0 = b"00000000000000000000000000000000"; let big_value1 = b"11111111111111111111111111111111"; - let mut memdb = MemoryDB::new(); + let mut memdb = MemoryDB::::new(); let mut root = H256::new(); let mut t = TrieDBMut::new(&mut memdb, &mut root); t.insert(&[0x01u8, 0x23], big_value0).unwrap(); @@ -1153,7 +1176,7 @@ mod tests { fn insert_duplicate_value() { let big_value = b"00000000000000000000000000000000"; - let mut memdb = MemoryDB::new(); + let mut memdb = MemoryDB::::new(); let mut root = H256::new(); let mut t = TrieDBMut::new(&mut memdb, &mut root); t.insert(&[0x01u8, 0x23], big_value).unwrap(); @@ -1166,15 +1189,15 @@ mod tests { #[test] fn test_at_empty() { - let mut memdb = MemoryDB::new(); + let mut memdb = MemoryDB::::new(); let mut root = H256::new(); let t = TrieDBMut::new(&mut memdb, &mut root); - assert_eq!(t.get(&[0x5]), Ok(None)); + assert_eq!(t.get(&[0x5]).unwrap(), None); } #[test] fn test_at_one() { - let mut memdb = MemoryDB::new(); + let mut memdb = MemoryDB::::new(); let mut root = H256::new(); let mut t = TrieDBMut::new(&mut memdb, &mut root); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); @@ -1185,7 +1208,7 @@ mod tests { #[test] fn test_at_three() { - let mut memdb = MemoryDB::new(); + let mut memdb = MemoryDB::::new(); let mut root = H256::new(); let mut t = TrieDBMut::new(&mut memdb, &mut root); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); @@ -1194,12 +1217,12 @@ mod tests { assert_eq!(t.get(&[0x01, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0x01u8, 0x23])); assert_eq!(t.get(&[0xf1, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0xf1u8, 0x23])); assert_eq!(t.get(&[0x81, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0x81u8, 0x23])); - assert_eq!(t.get(&[0x82, 0x23]), Ok(None)); + assert_eq!(t.get(&[0x82, 0x23]).unwrap(), None); t.commit(); assert_eq!(t.get(&[0x01, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0x01u8, 0x23])); assert_eq!(t.get(&[0xf1, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0xf1u8, 0x23])); assert_eq!(t.get(&[0x81, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0x81u8, 0x23])); - assert_eq!(t.get(&[0x82, 0x23]), Ok(None)); + assert_eq!(t.get(&[0x82, 0x23]).unwrap(), None); } #[test] @@ -1215,14 +1238,14 @@ mod tests { }.make_with(&mut seed); let real = trie_root(x.clone()); - let mut memdb = MemoryDB::new(); + let mut memdb = MemoryDB::::new(); let mut root = H256::new(); - let mut memtrie = populate_trie(&mut memdb, &mut root, &x); + let mut memtrie = populate_trie::<_, RlpCodec>(&mut memdb, &mut root, &x); let mut y = x.clone(); y.sort_by(|ref a, ref b| a.0.cmp(&b.0)); - let mut memdb2 = MemoryDB::new(); + let mut memdb2 = MemoryDB::::new(); let mut root2 = H256::new(); - let mut memtrie_sorted = populate_trie(&mut memdb2, &mut root2, &y); + let mut memtrie_sorted = populate_trie::<_, RlpCodec>(&mut memdb2, &mut root2, &y); if *memtrie.root() != real || *memtrie_sorted.root() != real { println!("TRIE MISMATCH"); println!(""); @@ -1242,15 +1265,15 @@ mod tests { #[test] fn test_trie_existing() { + let mut db = MemoryDB::::new(); let mut root = H256::new(); - let mut db = MemoryDB::new(); { let mut t = TrieDBMut::new(&mut db, &mut root); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); } { - let _ = TrieDBMut::from_existing(&mut db, &mut root); + let _ = TrieDBMut::from_existing(&mut db, &mut root); } } @@ -1265,7 +1288,7 @@ mod tests { count: 4, }.make_with(&mut seed); - let mut db = MemoryDB::new(); + let mut db = MemoryDB::::new(); let mut root = H256::new(); let mut t = TrieDBMut::new(&mut db, &mut root); for &(ref key, ref value) in &x { @@ -1279,7 +1302,7 @@ mod tests { } assert!(t.is_empty()); - assert_eq!(*t.root(), KECCAK_NULL_RLP); + assert_eq!(*t.root(), RlpCodec::HASHED_NULL_NODE); } #[test] @@ -1293,7 +1316,7 @@ mod tests { count: 4, }.make_with(&mut seed); - let mut db = MemoryDB::new(); + let mut db = MemoryDB::::new(); let mut root = H256::new(); let mut t = TrieDBMut::new(&mut db, &mut root); for &(ref key, ref value) in &x { diff --git a/util/plain_hasher/Cargo.toml b/util/plain_hasher/Cargo.toml index d909f8f9d6b..9b2cd55033f 100644 --- a/util/plain_hasher/Cargo.toml +++ b/util/plain_hasher/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "plain_hasher" description = "Hasher for 32-bit keys." -version = "0.1.0" +version = "0.2.0" authors = ["Parity Technologies "] license = "MIT" keywords = ["hash", "hasher"] @@ -10,3 +10,4 @@ homepage = "https://github.com/paritytech/plain_hasher" [dependencies] crunchy = "0.1.6" ethereum-types = "0.3" +hashdb = { version = "0.2.0", path = "../hashdb" } \ No newline at end of file diff --git a/util/plain_hasher/src/lib.rs b/util/plain_hasher/src/lib.rs index 74e2225dc8f..4a8a1044162 100644 --- a/util/plain_hasher/src/lib.rs +++ b/util/plain_hasher/src/lib.rs @@ -17,11 +17,12 @@ #[macro_use] extern crate crunchy; extern crate ethereum_types; +extern crate hashdb; use ethereum_types::H256; -use std::collections::{HashMap, HashSet}; +// use hashdb::Hasher; use std::hash; - +use std::collections::{HashMap, HashSet}; /// Specialized version of `HashMap` with H256 keys and fast hashing function. pub type H256FastMap = HashMap>; /// Specialized version of `HashSet` with H256 keys and fast hashing function. diff --git a/util/rlp/benches/rlp.rs b/util/rlp/benches/rlp.rs index 6aeabaf5de1..7f2e9f64591 100644 --- a/util/rlp/benches/rlp.rs +++ b/util/rlp/benches/rlp.rs @@ -14,13 +14,13 @@ #![feature(test)] -extern crate test; -extern crate ethcore_bigint as bigint; +extern crate ethereum_types; extern crate rlp; +extern crate test; -use test::Bencher; -use bigint::prelude::U256; +use ethereum_types::U256; use rlp::{RlpStream, Rlp}; +use test::Bencher; #[bench] fn bench_stream_u64_value(b: &mut Bencher) { @@ -38,7 +38,7 @@ fn bench_decode_u64_value(b: &mut Bencher) { // u64 let data = vec![0x88, 0x10, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]; let rlp = Rlp::new(&data); - let _: u64 = rlp.as_val(); + let _: u64 = rlp.as_val().unwrap(); }); } @@ -61,7 +61,7 @@ fn bench_decode_u256_value(b: &mut Bencher) { 0x30, 0x40, 0x50, 0x60, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xf0]; let rlp = Rlp::new(&data); - let _ : U256 = rlp.as_val(); + let _ : U256 = rlp.as_val().unwrap(); }); } @@ -83,11 +83,11 @@ fn bench_decode_nested_empty_lists(b: &mut Bencher) { // [ [], [[]], [ [], [[]] ] ] let data = vec![0xc7, 0xc0, 0xc1, 0xc0, 0xc3, 0xc0, 0xc1, 0xc0]; let rlp = Rlp::new(&data); - let _v0: Vec = rlp.at(0).as_list(); - let _v1: Vec = rlp.at(1).at(0).as_list(); - let nested_rlp = rlp.at(2); - let _v2a: Vec = nested_rlp.at(0).as_list(); - let _v2b: Vec = nested_rlp.at(1).at(0).as_list(); + let _v0: Vec = rlp.at(0).unwrap().as_list().unwrap(); + let _v1: Vec = rlp.at(1).unwrap().at(0).unwrap().as_list().unwrap(); + let nested_rlp = rlp.at(2).unwrap(); + let _v2a: Vec = nested_rlp.at(0).unwrap().as_list().unwrap(); + let _v2b: Vec = nested_rlp.at(1).unwrap().at(0).unwrap().as_list().unwrap(); }); } diff --git a/util/rlp/src/lib.rs b/util/rlp/src/lib.rs index b416b1c25b0..08c36522dab 100644 --- a/util/rlp/src/lib.rs +++ b/util/rlp/src/lib.rs @@ -43,8 +43,8 @@ mod rlpin; mod stream; mod impls; -use std::borrow::Borrow; use elastic_array::ElasticArray1024; +use std::borrow::Borrow; pub use error::DecoderError; pub use traits::{Decodable, Encodable}; diff --git a/util/rlp/src/stream.rs b/util/rlp/src/stream.rs index 550ede03991..13ccddaa721 100644 --- a/util/rlp/src/stream.rs +++ b/util/rlp/src/stream.rs @@ -58,6 +58,50 @@ impl RlpStream { stream } + /// Apends null to the end of stream, chainable. + /// + /// ```rust + /// extern crate rlp; + /// use rlp::*; + /// + /// fn main () { + /// let mut stream = RlpStream::new_list(2); + /// stream.append_empty_data().append_empty_data(); + /// let out = stream.out(); + /// assert_eq!(out, vec![0xc2, 0x80, 0x80]); + /// } + /// ``` + pub fn append_empty_data(&mut self) -> &mut Self { + // self push raw item + self.buffer.push(0x80); + + // try to finish and prepend the length + self.note_appended(1); + + // return chainable self + self + } + + /// Drain the object and return the underlying ElasticArray. Panics if it is not finished. + pub fn drain(self) -> ElasticArray1024 { + match self.is_finished() { + true => self.buffer, + false => panic!() + } + } + + /// Appends raw (pre-serialised) RLP data. Use with caution. Chainable. + pub fn append_raw<'a>(&'a mut self, bytes: &[u8], item_count: usize) -> &'a mut Self { + // push raw items + self.buffer.append_slice(bytes); + + // try to finish and prepend the length + self.note_appended(item_count); + + // return chainable self + self + } + /// Appends value to the end of stream, chainable. /// /// ```rust @@ -145,42 +189,6 @@ impl RlpStream { self } - /// Apends null to the end of stream, chainable. - /// - /// ```rust - /// extern crate rlp; - /// use rlp::*; - /// - /// fn main () { - /// let mut stream = RlpStream::new_list(2); - /// stream.append_empty_data().append_empty_data(); - /// let out = stream.out(); - /// assert_eq!(out, vec![0xc2, 0x80, 0x80]); - /// } - /// ``` - pub fn append_empty_data(&mut self) -> &mut RlpStream { - // self push raw item - self.buffer.push(0x80); - - // try to finish and prepend the length - self.note_appended(1); - - // return chainable self - self - } - - /// Appends raw (pre-serialised) RLP data. Use with caution. Chainable. - pub fn append_raw<'a>(&'a mut self, bytes: &[u8], item_count: usize) -> &'a mut RlpStream { - // push raw items - self.buffer.append_slice(bytes); - - // try to finish and prepend the length - self.note_appended(item_count); - - // return chainable self - self - } - /// Appends raw (pre-serialised) RLP data. Checks for size oveflow. pub fn append_raw_checked<'a>(&'a mut self, bytes: &[u8], item_count: usize, max_size: usize) -> bool { if self.estimate_size(bytes.len()) > max_size { @@ -215,7 +223,7 @@ impl RlpStream { /// ```rust /// extern crate rlp; /// use rlp::*; - /// + /// /// fn main () { /// let mut stream = RlpStream::new_list(3); /// stream.append(&"cat"); @@ -300,14 +308,6 @@ impl RlpStream { BasicEncoder::new(self) } - /// Drain the object and return the underlying ElasticArray. - pub fn drain(self) -> ElasticArray1024 { - match self.is_finished() { - true => self.buffer, - false => panic!() - } - } - /// Finalize current ubnbound list. Panics if no unbounded list has been opened. pub fn complete_unbounded_list(&mut self) { let list = self.unfinished_lists.pop().expect("No open list."); diff --git a/util/rlp/tests/tests.rs b/util/rlp/tests/tests.rs index 041c267667d..7aa2920c60c 100644 --- a/util/rlp/tests/tests.rs +++ b/util/rlp/tests/tests.rs @@ -423,4 +423,3 @@ fn test_rlp_stream_unbounded_list() { stream.complete_unbounded_list(); assert!(stream.is_finished()); } - diff --git a/whisper/Cargo.toml b/whisper/Cargo.toml index e503a74fd6d..cdc83743adc 100644 --- a/whisper/Cargo.toml +++ b/whisper/Cargo.toml @@ -15,7 +15,7 @@ hex = "0.2" log = "0.3" mem = { path = "../util/mem" } ordered-float = "0.5" -parking_lot = "0.5" +parking_lot = "0.6" rand = "0.4" rlp = { path = "../util/rlp" } serde = "1.0"